嵌套 XML 属性的正则表达式
Regex for nested XML attributes
假设我有以下字符串:
"<aa v={<dd>sop</dd>} z={ <bb y={ <cc x={st}>ABC</cc> }></bb> }></aa>"
如何编写通用正则表达式(标签名称更改、属性名称更改)以匹配 {}
中的内容,<dd>sop</dd>
或 <bb y={ <cc x={st}>ABC</cc> }></bb>
。
我写的正则表达式 "(\s*\w*=\s*\{)\s*(<.*>)\s*(\})"
匹配
"<dd>sop</dd>} z={ <bb y={ <cc x={st}>ABC</cc> }></bb>"
这是不正确的。
您正在尝试处理平衡的括号组。这需要递归正则表达式。根据定义,递归正则表达式是不规则的。无论如何,有些语言支持它们,例如Perl,PHP,ruby。 This 是关于该主题的很好的教程。
通常,您应该使用成熟的解析器(如 yacc)提取此类信息。
这是一个可以处理 非平衡 大括号的正则表达式:([ =]*)=(\{[^}]*\})
。这将匹配 {<dd>sop</dd>}
和 {st}
,这是正确的。不幸的是,它也会匹配 { <bb y={ <cc x={st}
,这不是您想要的。
在通用正则表达式中,无法很好地处理嵌套。因此,当出现这样的问题时,所有的胜利 - 永远不要使用正则表达式来解析 XML/HTML.
在一些简单的情况下,它可能是有利的。如果像您的示例一样,嵌套的层数有限,您可以非常简单地为每一层添加一个正则表达式。
现在让我们分步进行。要处理第一个未嵌套的属性,您可以使用
{[^}]*}
这匹配一个起始大括号,后跟任意数量的任何东西 但 一个右大括号,最后是一个右大括号。为了简单起见,我将把它的核心放在一个非捕获组中,比如
{(?:[^}])*}
这是因为在插入备用的时候,需要它。
如果您现在允许除了右大括号 ([^}]
) 之外的任何东西也是另一个嵌套的大括号 并简单地加入第一个正则表达式,例如
{(?:{[^}]*}|[^}])*}
^^^^^^^ original regex inserted as alternative (to it self)
它允许一层嵌套。再次做同样的事情,加入这个正则表达式作为自身的替代,比如
{(?:{(?:{[^}]*}|[^}])*}|{[^}]*}|[^}])*}
^^^^^^^^^^^^^^^ previous level repeated
将允许另一层嵌套。如果需要,可以对更多级别重复此操作。
虽然这不处理属性名称和其他内容的捕获,因为您的问题不太清楚您想要什么,但它向您展示了一种方式(i.m.o。最容易理解的, 或... :P) 来处理正则表达式中的嵌套。
You can see it handle your example here at regex101.
此致
假设我有以下字符串:
"<aa v={<dd>sop</dd>} z={ <bb y={ <cc x={st}>ABC</cc> }></bb> }></aa>"
如何编写通用正则表达式(标签名称更改、属性名称更改)以匹配 {}
中的内容,<dd>sop</dd>
或 <bb y={ <cc x={st}>ABC</cc> }></bb>
。
我写的正则表达式 "(\s*\w*=\s*\{)\s*(<.*>)\s*(\})"
匹配
"<dd>sop</dd>} z={ <bb y={ <cc x={st}>ABC</cc> }></bb>"
这是不正确的。
您正在尝试处理平衡的括号组。这需要递归正则表达式。根据定义,递归正则表达式是不规则的。无论如何,有些语言支持它们,例如Perl,PHP,ruby。 This 是关于该主题的很好的教程。
通常,您应该使用成熟的解析器(如 yacc)提取此类信息。
这是一个可以处理 非平衡 大括号的正则表达式:([ =]*)=(\{[^}]*\})
。这将匹配 {<dd>sop</dd>}
和 {st}
,这是正确的。不幸的是,它也会匹配 { <bb y={ <cc x={st}
,这不是您想要的。
在通用正则表达式中,无法很好地处理嵌套。因此,当出现这样的问题时,所有的胜利 - 永远不要使用正则表达式来解析 XML/HTML.
在一些简单的情况下,它可能是有利的。如果像您的示例一样,嵌套的层数有限,您可以非常简单地为每一层添加一个正则表达式。
现在让我们分步进行。要处理第一个未嵌套的属性,您可以使用
{[^}]*}
这匹配一个起始大括号,后跟任意数量的任何东西 但 一个右大括号,最后是一个右大括号。为了简单起见,我将把它的核心放在一个非捕获组中,比如
{(?:[^}])*}
这是因为在插入备用的时候,需要它。
如果您现在允许除了右大括号 ([^}]
) 之外的任何东西也是另一个嵌套的大括号 并简单地加入第一个正则表达式,例如
{(?:{[^}]*}|[^}])*}
^^^^^^^ original regex inserted as alternative (to it self)
它允许一层嵌套。再次做同样的事情,加入这个正则表达式作为自身的替代,比如
{(?:{(?:{[^}]*}|[^}])*}|{[^}]*}|[^}])*}
^^^^^^^^^^^^^^^ previous level repeated
将允许另一层嵌套。如果需要,可以对更多级别重复此操作。
虽然这不处理属性名称和其他内容的捕获,因为您的问题不太清楚您想要什么,但它向您展示了一种方式(i.m.o。最容易理解的, 或... :P) 来处理正则表达式中的嵌套。
You can see it handle your example here at regex101.
此致