2017-08-24 120 views
0

我试图解析一个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>而无法匹配。

有谁知道我是否做错了,我能做些什么来解决它?谢谢!

回答

1

这里是一种与引入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表达式中删除前导.

+0

谢谢!我对xpath不太舒服,并且在Nokogiri遇到麻烦,但我会再试一次。 – mcheah

0

第一个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解析器可能是一个更好的选择。