2010-07-09 88 views
1

我需要一个函数或一些正则表达式来分割字符串中的空格,但将HTML标记视为单词。拆分单词但不包含HTML如果它包含HTML

$str = 'one two <a href="">three</a> four'; 
$x = explode(" ", $str); 
print_r($x); 

/* Returns: 
    Array 
(
    [0] => one 
    [1] => two 
    [2] => <a 
    [3] => href="">three</a> 
    [4] => four 
) 

Looking for way to return: 

Array 
(
    [0] => one 
    [1] => two 
    [2] => <a href="">three</a> 
    [3] => four 
) 

*/ 

任何想法?谢谢

+0

我正在写一个函数,这个..应该就会完成.. – Fosco 2010-07-09 13:26:33

回答

2

这是简单一些,然后上面,还没有完全测试,但给它一个镜头。

$str = 'one two <a href="">three</a> four'; 

if(preg_match_all('%(<[^<]+.*?>|[^\s]+)%', $str, $matches)) { 
    array_shift($matches); 
    print_r($matches); 
} 

这里是另一个我5分钟左右的作品好一点的测试版本:

$str = 'one two <a href="omfg hi I have spaces"> three</a> four <script type="javascript"> var a = "hello"; </script><random tag>la la la la<nested>hello?</nested></random tag>'; 

if(preg_match_all('%(<[^<]+.*?>|[^\s]+)%', preg_replace('%([\s]\<|\>[\s])%', '$1', $str), $matches)) { 
    array_shift($matches); 
    echo '<pre>'; 
    print_r($matches); 
    echo '</pre>'; 
} 
+0

可以工作,但如果字符串中有
则失败 – fire 2010-07-09 16:10:34

0

在使用爆炸之前和之后,可以对字符串进行正则表达式替换。

所以它会进入爆炸一样

<a_href="">test</a> 

超越任何简单的情况下,虽然你在谈论解析HTML这不是做正则表达式的好事。

这里有很多关于解析HTML的问题。也许你可以适应他们。

2
preg_split('/(<([A-Z][A-Z0-9]*)\b[^>]*>(.*?)</\1>)|| /, $text) 

这有时会奏效。它分成一个标签集,或者一个空间。

但是,你想要的不是那么简单。您应该涵盖所有嵌套标签的情况,内容有空格的标签([a href] Foo Bar Baz [/ a])等等。 为此,你最好实现一个合适的XML(html)解析器。

但是在我看来你对这个数组有目的。它是数数“单词”吗?如果是这样,解决方案将是一个更简单的函数调用,从文本中剥离所有HTML(strip_tags()),然后应用您的wordsplitter并对它们进行计数。

0

我编写并测试了这个自定义函数。试试看,让我知道你的想法。

function fireSplit($str) { 
    if (strpos($str,"<") === FALSE) return explode(" ",$str); 
    $str = trim($str); 
    $out = array(); 
    $curIdx = 0; 
    $endIdx = strlen($str) -1; 

    while ($curIdx <= $endIdx) { 
     if (substr($str,$curIdx,1) == " ") { 
       $curIdx += 1; 
       continue; 
     } 
     $nextspace = strpos($str," ",$curIdx); 
     $nexttag = strpos($str,"<",$curIdx); 
     $nexttag2 = strpos($str,"/",$nexttag); 
     $nexttag3 = strpos($str,">",$nexttag2); 

     if ($nextspace === FALSE) { 
       $out[] = substr($str,$curIdx); 
       $curIdx = $endIdx + 1; 
       continue; 
     } 

     if ($nexttag !== FALSE && $nexttag < $nextspace && $nexttag2 !== FALSE && $nexttag3 !== FALSE) { 
       $out[] = substr($str,$curIdx,($nexttag3 - $curIdx + 1)); 
       $curIdx = $nexttag3 + 1; 
     } else { 
       $out[] = substr($str,$curIdx,($nextspace - $curIdx)); 
       $curIdx = $nextspace; 
     } 
    } 
return $out; 
} 

我叫:

fireSplit("one two <a href=\"haha\">three</a> four"); 
fireSplit("a <b>strong</b> c d e f"); 

,它返回:

array(4) { 
    [0]=> 
    string(3) "one" 
    [1]=> 
    string(3) "two" 
    [2]=> 
    string(24) "<a href="haha">three</a>" 
    [3]=> 
    string(4) "four" 
} 

array(6) { 
    [0]=> 
    string(1) "a" 
    [1]=> 
    string(13) "<b>strong</b>" 
    [2]=> 
    string(1) "c" 
    [3]=> 
    string(1) "d" 
    [4]=> 
    string(1) "e" 
    [5]=> 
    string(1) "f" 
} 
+0

附加测试可能发现一个或两个我没有考虑的情景......我只想到了一个,标签结束后的下一个字符不是空格。 – Fosco 2010-07-09 13:48:28

+0

我更新了函数以解释我上次评论中的错过情景。 – Fosco 2010-07-09 13:59:31

+0

@Fosco邪恶的功能取$ str ='a c d e f';我得到致命错误:允许的内存大小为104857600字节,因此它必须在某处泄漏内存?! – fire 2010-07-09 15:54:15