在前面和后面匹配的Ruby中的负向前瞻
问题描述:
我试图解析一个XML文档(特别是一个Sublime颜色主题),并且我试图使用负向前视来阻止我不想要的匹配,但它似乎没有正常工作。在前面和后面匹配的Ruby中的负向前瞻
的模式如下:
/
<key>name<\/key>
.*? # find as little as possible including new lines
<string>(.*?)<\/string> # Match the name of this color Rule
.*?
<dict>
((?!<\/dict>).)*? # After the second opening <dict>, do not allow a closing </dict>
<key>foreground<\/key>
.*?
<string>(.*?)<\/string> # Match the hex code for the name found in Match 1.
/mx # Treat a newline as a character matched by .
# Ignore Whitespace, comments.
正被匹配的字符串是:
<dict>
<key>name</key>
<string>**Variable**</string>
<key>scope</key>
<string>variable</string>
<key>settings</key>
<dict>
<key>fontStyle</key>
<string></string>
</dict>
</dict>
<dict>
<key>name</key>
<string>Keyword</string>
<key>scope</key>
<string>keyword - (source.c keyword.operator | source.c++ keyword.operator | source.objc keyword.operator | source.objc++ keyword.operator), keyword.operator.word</string>
<key>settings</key>
<dict>
<key>foreground</key>
<string>**#F92672**</string>
的整个字符串匹配时,与**Variable**
作为第一捕获组和**#F92672**
作为第二。理想情况下,我希望在第二部分中第一个捕获组成为Keyword
。我认为负面预测的存在意味着第一部分不会成为比赛的一部分,因为它会看到</dict>
而无法匹配。
有谁知道我是否做错了,我能做些什么来解决它?谢谢!
答
这里是一种与引入nokogiri做到这一点:
require 'nokogiri'
theme = Nokogiri::XML.fragment(xml)
puts theme.xpath('./dict[1]/key[text()="name"]/following-sibling::string[1]').text
#=> "**Variable**"
puts theme.xpath('.//dict[preceding-sibling::key[1][text()="settings"]]/string').text
#=> "**#F92672**"
的第一个XPath取第一dict
并发现key
含有“名称”,然后采取下列string
元素的文本。
第二个XPath在包含“设置”的key
之后立即寻找dict
,并检索其string
元素的文本。
请注意,如果您解析完整文档而不是给定片段,则需要进行一些更改,例如将呼叫更改为theme = Nokogiri::XML.parse(xml)
,并从XPath表达式中删除前导.
。
答
第一个dict
与字符串**Variable**
和第二个与Keyword
具有相同的结构。而且你想通过负面预测来区分它们,但这是不可能的。
变化((?!<\/dict>).)*?
到(((?!<\/dict>).)*?)
调试 ,你可以看到新的基团含量
result="
<key>name</key>
<string>Keyword</string>
<key>scope</key>
<string>keyword - (source.c keyword.operator | source.c++ keyword.operator | source.objc keyword.operator | source.objc++ keyword.operator), keyword.operator.word</string>
<key>settings</key>
<dict>
"
这满足你的负面先行。
即使添加更多条件(仅使用结构作为条件而不是内容),因为相同的结构,**Variable**
将始终在**#F92672**
之前。
因此使用xml解析器可能是一个更好的选择。
谢谢!我对xpath不太舒服,并且在Nokogiri遇到麻烦,但我会再试一次。 – mcheah