preg_match_all:获取引号内的文本,html标记中除外

preg_match_all:获取引号内的文本,html标记中除外,html,regex,tags,quotes,Html,Regex,Tags,Quotes,我最近使用了一种模式,用成对的开始/结束双引号替换直接双引号 $string = preg_replace('/(\")([^\"]+)(\")/','“$2”',$string); 如果$string是一个句子,甚至是一个段落,它就可以正常工作 但是 我的函数可以被调用到一块HTML代码的作业中,它不再作为例外工作: $string = preg_replace('/(\")([^\"]+)(\")/','“$2”','<a href="page.html">Somethi

我最近使用了一种模式,用成对的开始/结束双引号替换直接双引号

$string = preg_replace('/(\")([^\"]+)(\")/','“$2”',$string);
如果$string是一个句子,甚至是一个段落,它就可以正常工作

但是

我的函数可以被调用到一块HTML代码的作业中,它不再作为例外工作:

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

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

这是一个问题

所以我想我可以分两步完成:提取标签中的文本,然后替换引号

我试过这个

$pattern='/<[^>]+>(.*)<\/[^>]+>/';
$pattern='/]+>(.*]+>”;
例如,如果字符串是

$string='<a href="page.html">Something "with" quotes</a>';
$string='';
但它不适用于以下字符串:

$string='Something "with" quotes <a href="page.html">Something "with" quotes</a>';
$string='Something'加上“引号”;
有什么想法吗


Bertrand

我想通常的回答是……正如已经发生的那样,您不应该通过正则表达式解析HTML。您可以查看以提取文本并应用正则表达式,从您已经说过的内容来看,它似乎工作得很好


本教程将为您指明正确的方向。

我确信这将以一场火焰之战结束,但这是可行的:

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);
}
有了costum状态机,你甚至可以不用先替换,然后再替换回来。我还是建议使用解析器。

我终于找到了一种方法:

  • 提取任何标记(如果有)的内部或外部(之前、之后)的文本
  • 使用回调按对查找引号并替换它们
  • 代码

    $string=preg\u replace\u回调('/[^]*(?!([^)/sim',创建函数('$matches',返回preg\u replace(\'/(\'')([^\']+)(\'')/\',\'“$2”,$matches[0]),$string);
    
    Bertrand,重新提出这个问题,因为它有一个简单的解决方案,可以让您一次完成替换,而无需回调。(在对有关的一般问题进行研究时发现了您的问题。)

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

    <[^>]*>(*SKIP)(*F)|"([^"]*)"
    
    ]*>(*跳过)(*F)|“([^”]*)”
    
    交替的左侧匹配complete
    ,然后故意失败。右侧匹配双引号字符串,我们知道它们是右侧字符串,因为它们没有与左侧的表达式匹配

    这段代码显示了如何使用正则表达式(请参见本部分底部的结果):


    @Kolink我知道会出现这种情况。这就是为什么我建议使用simplexml,只将其应用于文本,而不应用于属性。我必须“清理”的字符串是90%大小写中文本字段的值,在某些情况下,您有“位”“内部的html代码。这就是解析不合适的原因。如果
    'Something'加引号'
    ,需要什么输出?
    'Something'加引号'
    'Something'使用引号“
    ?谢谢,但当我需要解析某些代码时,我会使用解析器。在这种情况下,解析代码不会帮助我用其他字符替换某些字符。我尝试过,它很有效。谢谢。问题是,在90%的时间里,我只得到一个字符串(文本输入的值)使用一个字符串或几个标记的解析器实际上需要做更多的工作。这个正则表达式不适用于完整的html页面。
    $string = preg_replace_callback('/[^<>]*(?!([^<]+)?>)/sim', create_function('$matches',  'return preg_replace(\'/(\")([^\"]+)(\")/\', \'“$2”\', $matches[0]);'), $string);
    
    <[^>]*>(*SKIP)(*F)|"([^"]*)"
    
    <?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";
    ?>