PHP正则表达式,不在另一个标签中的标签

时间:2017-09-06 07:55:07

标签: php regex

我需要一个匹配标签内容的正则表达式,它不是另一个标签的一部分。不满意我不能使用PHP DOM Parser,因为标签的内容有时包含非常特殊的字符。

这是传入输入的示例:

<cherry>test</cherry>
<banana>
    <cherry>test</cherry>
    some text
</banana>

这是我当前的正则表达式,但它也会匹配标记内的标记

 (<cherry>)(.*?)(<\/cherry>)

如何排除其他标签中的匹配?

我已经尝试了很多......

2 个答案:

答案 0 :(得分:2)

为什么不使用DOMDocument类而不是正则表达式。只需加载您的DOM,然后使用getElementsByTagName获取您的代码。通过这种方式,您可以排除任何其他您不想要的标记,只能获取您所做的标记。

示例

<?php
$xml = <<< XML
<?xml version="1.0" encoding="utf-8"?>
<books>
 <book>Patterns of Enterprise Application Architecture</book>
 <book>Design Patterns: Elements of Reusable Software Design</book>
 <book>Clean Code</book>
</books>
XML;

$dom = new DOMDocument;
$dom->loadXML($xml);
$books = $dom->getElementsByTagName('book');
foreach ($books as $book) {
    echo $book->nodeValue, PHP_EOL;
}
?>

阅读材料

DOMDocument

答案 1 :(得分:0)

在假设下,你只需要顶级数学标签的内容而没有任何其他东西,你到目前为止都无法做到这一点,因为数学标签包含无效的xml,因此任何xml-parser都会放弃...(正如问题和评论中所述)

干净的方法可能是,使用一些容错的xml-parser(或容错模式)或者之前整理输入。但是,这些方法都可能“破坏”内容。

如果剩下的xml也无效或者你的数学,那么hacky和可能很脏的方法可能会出现以下其他问题, 尤其 标签是嵌套的(这将导致xml-parser在步骤2中失败):

  1. 通过占位符替换任何<math>.*</math>(ungreedy)(最好是一些独特的uniqid可能有帮助,但一个简单的计数器可能就足够了)通过preg_replace_callback或其他东西
  2. 使用通用的xml-parser解析文档(根据需要将其包装在某个根标记中)
  3. 获取根节点/所有根节点的所有子节点,查看在步骤1中生成的节点。
  4. 例如:

    <math>some invalid xml</math>
    <sometag>
        <math>more invalid xml</math>
        some text
    </sometag>
    

    替换为

    $replacements = [];
    $newcontent = preg_replace_callback(
           '/'.preg_quote('<math>','/').'(.*)'.preg_quote('</math>','/').'/siU',  
           function($hit) use ($replacements) { 
               $id = uniqid();
               $replacements[$id] = $hit[1];
               return '<math id="'.$id.'" />';
           },
           $originalcontent);
    

    将您的内容转换为:

    <math id="1stuniqid" />
    <sometag>
        <math id="2nduniqid" />
        some text
    </sometag>
    

    现在使用您选择的xml解析器并选择所有根级别/基本级别元素并查找/math/@id(我的XPath可能是错误的,根据需要进行调整)。结果应包含所有uniqids,您可以在替换数组中查找

    修复了

    编辑一些preg_quote个问题并使用了更多标准分隔符。