note 89092 added to function.preg-match-all
| From: | royaltm75 at NOSPAM dot gmail dot com | Date: | Sat, 21 Feb 2009 10:55:15 +0000 |
| Subject: | note 89092 added to function.preg-match-all | ||
| Groups: | php.notes | ||
| Request: | Send a blank email to php-notes+get-150914@lists.php.net to get a copy of this message | ||
The power of pregs is limited only by your *imagination* :)
I wrote this html2a() function using preg recursive match (?R) which provides quite safe and
bulletproof html/xml extraction:
<?php
function html2a ( $html ) {
if ( !preg_match_all( '
@
\<\s*?(\w+)((?:\b(?:\'[^\']*\'|"[^"]*"|[^\>])*)?)\>
((?:(?>[^\<]*)|(?R))*)
\<\/\s*?\\1(?:\b[^\>]*)?\>
|\<\s*(\w+)(\b(?:\'[^\']*\'|"[^"]*"|[^\>])*)?\/?\>
@uxis', $html = trim($html), $m, PREG_OFFSET_CAPTURE | PREG_SET_ORDER) )
return $html;
$i = 0;
$ret = array();
foreach ($m as $set) {
if ( strlen( $val = trim( substr($html, $i, $set[0][1] - $i) ) ) )
$ret[] = $val;
$val = $set[1][1] < 0
? array( 'tag' => strtolower($set[4][0]) )
: array( 'tag' => strtolower($set[1][0]), 'val' =>
html2a($set[3][0]) );
if ( preg_match_all( '
/(\w+)\s*(?:=\s*(?:"([^"]*)"|\'([^\']*)\'|(\w+)))?/usix
', isset($set[5]) && $set[2][1] < 0
? $set[5][0]
: $set[2][0]
,$attrs, PREG_SET_ORDER ) ) {
foreach ($attrs as $a) {
$val['attr'][$a[1]]=$a[count($a)-1];
}
}
$ret[] = $val;
$i = $set[0][1]+strlen( $set[0][0] );
}
$l = strlen($html);
if ( $i < $l )
if ( strlen( $val = trim( substr( $html, $i, $l - $i ) ) ) )
$ret[] = $val;
return $ret;
}
?>
Now let's try it with this example: (there are some really nasty xhtml compliant bugs, but ...
we shouldn't worry)
<?php
$html = <<<EOT
some leftover text...
< DIV class=noCompliant style = "text-align:left;" >
... and some other ...
< dIv > < empty> </ empty>
<p> This is yet another text <br >
that wasn't <b>compliant</b> too... <br />
</p>
<div class="noClass" > this one is better but we don't care anyway </div
><P>
<input type= "text" name ='my "name' value = "nothin
really." readonly>
end of paragraph </p> </Div> </div> some trailing text
EOT;
$a = html2a($html);
//now we will make some neat html out of it
echo a2html($a);
function a2html ( $a, $in = "" ) {
if ( is_array($a) ) {
$s = "";
foreach ($a as $t)
if ( is_array($t) ) {
$attrs="";
if ( isset($t['attr']) )
foreach( $t['attr'] as $k => $v )
$attrs.=" ${k}=".( strpos( $v, '"' )!==false ?
"'$v'" : "\"$v\"" );
$s.= $in."<".$t['tag'].$attrs.( isset( $t['val'] ) ?
">\n".a2html( $t['val'], $in." "
).$in."</".$t['tag'] : "/" ).">\n";
} else
$s.= $in.$t."\n";
} else {
$s = empty($a) ? "" : $in.$a."\n";
}
return $s;
}
?>
This produces:
some leftover text...
<div class="noCompliant" style="text-align:left;">
... and some other ...
<div>
<empty>
</empty>
<p>
This is yet another text
<br/>
that wasn't
<b>
compliant
</b>
too...
<br/>
</p>
<div class="noClass">
this one is better but we don't care anyway
</div>
<p>
<input type="text" name='my "name' value="nothin
really." readonly="readonly"/>
end of paragraph
</p>
</div>
</div>
some trailing text
----
Server IP: 82.177.164.100
Probable Submitter: 85.222.27.82
----
Manual Page -- http://www.php.net/manual/en/function.preg-match-all.php
Edit -- https://master.php.net/note/edit/89092
Del: integrated -- https://master.php.net/note/delete/89092/integrated
Del: useless -- https://master.php.net/note/delete/89092/useless
Del: bad code -- https://master.php.net/note/delete/89092/bad+code
Del: spam -- https://master.php.net/note/delete/89092/spam
Del: non-english -- https://master.php.net/note/delete/89092/non-english
Del: in docs -- https://master.php.net/note/delete/89092/in+docs
Del: other reasons-- https://master.php.net/note/delete/89092
Reject -- https://master.php.net/note/reject/89092
Search -- https://master.php.net/manage/user-notes.php