preg_match_all:除了html标签之外,在引号内获取文本

时间:2013-09-25 14:19:20

标签: html regex tags quotes

我最近使用了一种模式来用成对的开/关双引号替换直双引号。

$string = preg_replace('/(\")([^\"]+)(\")/','“$2”',$string);

当$ string是一个句子,甚至是段落时,它工作正常。

但是...

我的函数可以被调用到一大堆HTML代码的作业,并且它不再作为例外工作了:

$string    = preg_replace('/(\")([^\"]+)(\")/','“$2”','<a href="page.html">Something "with" quotes</a>');

返回

<a href=“page.html”>Something “with” quotes</a>

那是一个问题...

所以我认为我可以通过两次传递:在标签中提取文本,然后替换引号。

我试过这个

$pattern='/<[^>]+>(.*)<\/[^>]+>/';

例如,如果字符串是

,它就可以工作
$string='<a href="page.html">Something "with" quotes</a>';

但它不适用于像:

这样的字符串
$string='Something "with" quotes <a href="page.html">Something "with" quotes</a>';

有什么想法吗?

贝特朗

4 个答案:

答案 0 :(得分:1)

通常的回复我猜...因为它已经pointed out,所以你不应该通过正则表达式解析HTML。您可以查看PHP Simple DOM Parse来提取文本并应用您正在使用的正则表达式,这些正则表达式似乎正常工作。

This教程应该让你朝着正确的方向前进。

答案 1 :(得分:0)

我很确定这将以火焰战结束,但这有效:

echo do_replace('<a href="page.html">Something "with" quotes</a>')."\n";
echo do_replace('Something "with" quotes <a href="page.html">Something "with" quotes</a>')."\n";

function do_replace($string){
    preg_match_all('/<([^"]*?|"[^"]*")*>/', $string, $matches);
    $matches = array_flip($matches[0]);

    $uuid = md5(mt_rand());
    while(strpos($string, $uuid) !== false) $uuid = md5(mt_rand()); 
    // if you want better (time) garanties you could build a prefix tree and search it for a string not in it (would be O(n)

    foreach($matches as $key => $value)
        $matches[$key] = $uuid.$value;

    $string = str_replace(array_keys($matches), $matches, $string);
    $string = preg_replace('/\"([^\"<]+)\"/','&ldquo;$1&rdquo;', $string);
    return str_replace($matches, array_keys($matches), $string);
}

输出(我替换了&amp; ldquo;和&amp; rdquo;与):

<a href="page.html">Something “with” quotes</a>
Something “with” quotes <a href="page.html">Something “with” quotes</a>

使用costum状态机你甚至可以在没有第一次更换的情况下完成它而不是替换它。无论如何,我建议使用Parser。

答案 2 :(得分:0)

我终于找到了办法:

  1. 提取可以在任何标签(如果有)
  2. 内部或外部(之前,之后)的文本
  3. 使用回调按对查找引号并替换它们。
  4. $string = preg_replace_callback('/[^<>]*(?!([^<]+)?>)/sim', create_function('$matches',  'return preg_replace(\'/(\")([^\"]+)(\")/\', \'“$2”\', $matches[0]);'), $string);
    

答案 3 :(得分:0)

Bertrand,恢复了这个问题,因为它有一个简单的解决方案,让你可以一次性替换 - 不需要回调。 (在针对how to exclude patterns in regex的一般性问题进行一些研究时找到了您的问题。)

这是我们简单的正则表达式:

<[^>]*>(*SKIP)(*F)|"([^"]*)"

交替的左侧匹配完成<tags>然后故意失败。右侧匹配双引号字符串,我们知道它们是正确的字符串,因为它们与左侧的表达式不匹配。

此代码显示了如何使用正则表达式(请参阅online demo底部的结果):

<?php
$regex = '~<[^>]*>(*SKIP)(*F)|"([^"]*)"~';
$subject = 'Something "with" quotes <a href="page.html">Something "with" quotes</a>';
$replaced = preg_replace($regex,"“$1”",$subject);
echo $replaced."<br />\n";
?>

参考

How to match (or replace) a pattern except in situations s1, s2, s3...