我正在使用正则表达式来解析一些BBCode,因此正则表达式必须递归地工作以匹配其他人中的标签.大多数BBCode都有一个参数,有时引用它,但并非总是如此.
我正在使用的正则表达式的简化等效(使用html样式标记来减少所需的转义)是这样的:
'~<(\")?a(?(1)\1)> #Match the tag, and require a closing quote if an opening one provided
([^<]+ | (?R))* #Match the contents of the tag, including recursively
</a>~x'
Run Code Online (Sandbox Code Playgroud)
但是,如果我有一个如下所示的测试字符串:
<"a">Content<a>Also Content</a></a>
Run Code Online (Sandbox Code Playgroud)
它只匹配<a>Also Content</a>因为当它尝试从第一个标记匹配时,第一个匹配组,\1被设置为",并且当递归运行正则表达式以匹配内部标记时,这不会被覆盖,这意味着它不是引用,它不匹配,正则表达式失败.
如果相反我一直使用或不使用引号,它工作正常,但我不能确定那将是我必须解析的内容的情况.有什么方法可以解决这个问题吗?
完整的正则表达式,我使用,来匹配[spoiler]content[/spoiler],[spoiler=option]content[/spoiler]并且[spoiler="option"]content[/spoiler],是
"~\[spoiler\s*+ #Match the opening tag
(?:=\s*+(\"|\')?((?(1)(?!\\1).|[^\]]){0,100})(?(1)\\1))?+\s*\] #If an option exists, match that
(?:\ *(?:\n|<br />))?+ #Get rid of an extra new line before the start of the content if necessary
((?:[^\[\n]++ #Capture all characters until the closing tag
|\n(?!\[spoiler]) Capture new line separately so backtracking doesn't run away due to above
|\[(?!/?spoiler(?:\s*=[^\]*])?) #Also match all tags that aren't spoilers
|(?R))*+) #Allow the pattern to recurse - we also want to match spoilers inside spoilers,
# without messing up nesting
\n? #Get rid of an extra new line before the closing tag if necessary
\[/spoiler] #match the closing tag
~xi"
Run Code Online (Sandbox Code Playgroud)
不过还有其他一些错误.
最简单的解决方案是使用替代方案:
<(?:a|"a")>
([^<]++ | (?R))*
</a>
Run Code Online (Sandbox Code Playgroud)
但如果您确实不想重复该a部分,您可以执行以下操作:
<("?)a\1>
([^<]++ | (?R))*
</a>
Run Code Online (Sandbox Code Playgroud)
我刚刚将条件放入?组内。这次,捕获组始终匹配,但匹配可以为空,并且不再需要条件。
旁注:我应用了所有格量词来[^<]避免灾难性的回溯。
就您而言,我认为匹配通用标签比匹配特定标签更好。匹配所有标签,然后在代码中决定如何处理匹配。
这是完整的正则表达式:
\[
(?<tag>\w+) \s*
(?:=\s*
(?:
(?<quote>["']) (?<arg>.{0,100}?) \k<quote>
| (?<arg>[^\]]+)
)
)?
\]
(?<content>
(?:[^[]++ | (?R) )*+
)
\[/\k<tag>\]
Run Code Online (Sandbox Code Playgroud)
请注意,我添加了J选项 ( PCRE_DUPNAMES) 以便能够使用(?<arg>...)两次。
| 归档时间: |
|
| 查看次数: |
77 次 |
| 最近记录: |