正则表达式检测XML节点内的换行符

时间:2008-12-17 10:05:05

标签: xml regex

我在使用正则表达式时遇到了麻烦。我正在查看一组XML文件,并尝试检测包含换行符的特定节点内的一些文本。

以下是一些示例数据:

<item name='GenMsgText'><text>The signature will be discarded.</text></item>

<item name='GenMsgText'><text>The signature will be discarded.<break/>
Do you want to continue?</text></item>

在该示例中,我想仅捕获第二个节点中的文本。我想出了下面使用第二个正则表达式的解决方案,但我想知道我是否可以只用一个做同样的事情。

if ($content =~m{<item name='GenMsgText'>(<textlist>)?<text>(.*?)</text>}si)
  {
    $t = $2;
    if ($t =~m {\n}i)
    {
     print G $t."\n\n";
    }
}

这是一个不能重复使用的一次性工具,所以我想避免编写任何超过几行的解析代码。此外,上面的代码已经有效了,我问的是个人知识的问题而不是实际使用。

5 个答案:

答案 0 :(得分:5)

正则表达式不适合执行此任务,它无法很好地处理嵌套结构。如果你有一个DOM API,这个XPath会找到正确的节点:

如果您正在寻找<break/>元素,正如您的示例所示:

//item[@name='GenMsgText']/text[break]

对于“真实”换行符,为CR(0xD)或LF(0xA):

//item[@name='GenMsgText']/text[contains(., '&#xD;') or contains(., '&#xA;')]

答案 1 :(得分:3)

我应该考虑使用一些SAX解析器。正则表达式太脆弱,无法处理xml输入。

答案 2 :(得分:0)

我不确定,但认为这应该有效:

<item name='GenMsgText'>(<textlist>)?<text>(.*\n.*)</text>

答案 3 :(得分:0)

问题是你的模式.*?可以匹配尖括号和换行符。如果正则表达式开始匹配一个无法匹配的元素,那么就没有什么可以阻止它在下一个元素中继续匹配尝试。如果您知道文本中永远不会有尖括号,您可以将匹配限制为单个元素,如下所示:

<item name='GenMsgText'><text>([^<>\n]*\n[^<>]*)</text></item>

编辑:重要的是要注意Max和Kibbee提供的正则表达式应用于s模式(/ s,单行,DOTALL ......)。这就是阻止它们超出“item”元素末尾的原因:为了达到下一个元素,它们必须匹配元素之间的行分隔符。

但即使没有/ s修饰符,如果在连续的行上有两个没有内部换行符的元素(即,它们之间只有一个换行符),两个正则表达式都会失败。例如,这两行将匹配为一个:

<item name='GenMsgText'><text>foo</text></item>
<item name='GenMsgText'><text>bar</text></item>

另一方面,如果文本中有两行以上怎么办?其他正则表达式恰好匹配一个换行符,因此它们会失败。在我的正则表达式中,我明确匹配第一个换行符以确保有一个换行符,但如果还有换行符,则它们将与第二个字符类匹配:[^<>]*

这就是为什么我倾向于避免使用.*.*?

答案 4 :(得分:0)

与Alan提到的相同,您可以使用延迟捕获来仅在匹配结束文本语句之前捕获必要的数据

<item name='GenMsgText'><text>(.*?\n.*?)</text></item>

但同样,正则表达式可能完全是错误的工具,你应该使用正确的XML解析器。