preg_split但忽略XML和HTML实体

I using this php code to split a string roughly every 120 chars. It splits at the closest space. But it splits HTML and XML entities, so it sometimes outputs things like id="id">. How can I make it so it ignores XML and HTML entities, but does not remove them.

function splitWords($string, $max = 1)
{
    $words = preg_split( '/\s/', $string );
    $lines = array();
    $line = '';

    foreach ( $words as $k => $word ) {
        $newLine = $line . ' ' . $word;
        $length = strlen( $newLine );
        if ( $length <= $max ) {
            $line .= ' ' . $word;
        } else if ( $length > $max ) {
            if ( !empty( $line ) ) {
                $lines[] = trim( $line );
            }
            $line = $word;
        } else {
            $lines[] = trim( $line ) . ' ' . $word;
            $line = '';
        }
    }
    $lines[] = ( $line = trim( $line ) ) ? $line : $word;

    return $lines;
}

Description

I would change your split command to use tag substrings as a delimiter or the space.

This basic regex will:

  • match tags or will match spaces
  • it will not match spaces inside tags
  • will avoid many of the pitfalls with pattern matching html text

<\/?\w+(?=\s|>)(?:[^>=|&)]*|=\'[^\']*\'|="[^"]*"|=[^\'"][^\s>]*)*>|\s

enter image description here

With this regex you can do all sorts of crazy things depending on where you place the capturing paranthesse and the options used in preg_split.

Examples

Live Demo

Note that in this demo the anchor tags have some seriously difficult edge cases.

PHPv5.4.4 Code

<?php

$string = ' <a onmouseover=\' <a href="notreal.com">This is text inside an attribute</a> \' href=url.com>This is some inner text</a>This is outer text.

    <a onmouseover=\' a=1; href="www.NotYourURL.com" ; if (3 <a && href="www.NotYourURL.com" && id="revSAR" && 6 > 3) { funRotate(href) ; } ; \'  href=\'http://InterestedURL.com\' id=\'revSAR\'>
        I am the inner text too.
        </a>
';

echo "split retains all spaces
";
$array = preg_split ('/(<\/?\w+(?=\s|>)(?:[^>=|&)]*|=\'[^\']*\'|="[^"]*"|=[^\'"][^\s>]*)*>|\s)/', $string, 0, PREG_SPLIT_DELIM_CAPTURE); 
echo implode(",",$array);

echo "

split ignores spaces
";
$array = preg_split ('/(<\/?\w+(?=\s|>)(?:[^>=|&)]*|=\'[^\']*\'|="[^"]*"|=[^\'"][^\s>]*)*>)|\s/', $string, 0, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); 
echo implode(",",$array);

echo "

split ignores tags and spaces
";
$array = preg_split ('/<\/?\w+(?=\s|>)(?:[^>=|&)]*|=\'[^\']*\'|="[^"]*"|=[^\'"][^\s>]*)*>|\s/', $string, 0,  PREG_SPLIT_NO_EMPTY); 
echo implode(",",$array);

echo "

split ignores tags and retains spaces
";
$array = preg_split ('/<\/?\w+(?=\s|>)(?:[^>=|&)]*|=\'[^\']*\'|="[^"]*"|=[^\'"][^\s>]*)*>|(\s)/', $string, 0,  PREG_SPLIT_DELIM_CAPTURE); 
echo implode(",",$array);

Output

You're probably most interested in the third option "split ignores tags and spaces"

split retains all spaces
,   ,,<a onmouseover=' <a href="notreal.com">This is text inside an attribute</a> ' href=url.com>,This, ,is, ,some, ,inner, ,text,</a>,This, ,is, ,outer, ,text.,
,,
,,  ,,<a onmouseover=' a=1; href="www.NotYourURL.com" ; if (3 <a && href="www.NotYourURL.com" && id="revSAR" && 6 > 3) { funRotate(href) ; } ; '  href='http://InterestedURL.com' id='revSAR'>,,
,,  ,,  ,I, ,am, ,the, ,inner, ,text, ,too.,
,,  ,,  ,,</a>,,
,

split ignores spaces
<a onmouseover=' <a href="notreal.com">This is text inside an attribute</a> ' href=url.com>,This,is,some,inner,text,</a>,This,is,outer,text.,<a onmouseover=' a=1; href="www.NotYourURL.com" ; if (3 <a && href="www.NotYourURL.com" && id="revSAR" && 6 > 3) { funRotate(href) ; } ; '  href='http://InterestedURL.com' id='revSAR'>,I,am,the,inner,text,too.,</a>

split ignores tags and spaces
This,is,some,inner,text,This,is,outer,text.,I,am,the,inner,text,too.

split ignores tags and retains spaces
,   ,,This, ,is, ,some, ,inner, ,text,This, ,is, ,outer, ,text.,
,,
,,  ,,,
,,  ,,  ,I, ,am, ,the, ,inner, ,text, ,too.,
,,  ,,  ,,,
,