具有正向lookbehind的正则表达式,直到插值并与其他组合

时间:2013-04-14 15:08:45

标签: ruby regex oniguruma

使用正面的lookbehind,各个正则表达式匹配各自的字符串。合并后,他们不会。当通过移除正面观察来改变一个时它匹配。我不明白为什么并且想知道我可以解决它,因为我不希望这场比赛没有消耗。

value = /  # match a digit or something wrapped in quotes
        (?<value>
          \d+         # Match a digit
            |         # or
          (?:         # Match something wrapped in double quotes
            (?<=")  # <- this is the point of contention
            [^"]+     # captures anything not a "   
            (?=")
          )
            |         # or
          (?:         # Match something wrapped in single quotes
            (?<=')  # <- or this one
            [^']+     # captures anything not a '
            (?=')
          )
        )
      /x

value.match %q!'filename.rb'!
# => #<MatchData "filename.rb" value:"filename.rb">
value.match %q!"filename.rb"!
# => #<MatchData "filename.rb" value:"filename.rb">
value.match %q!66!
# => #<MatchData "66" value:"66">

因此它匹配任何数字或匹配引号中包含的任何内容。

long_option = /
        (?<long_option>
          (?<!
            (?:\-\-no\-)   # don't match --no-long
              |
            (?:\-\-\-)     # don't match ---long
          )
          (?<=\-\-)        # it must begin with --
          (?<key_name>
            [a-zA-Z]\w+    # capture the key name
          )
          \b
          (?!
            \-             # make sure it's not part of a longer key
          )
        )
      /x

long_option.match "--long"
# => #<MatchData "long" long_option:"long" key_name:"long">
long_option.match "---long"
# => nil
long_option.match "--long-"
# => nil
long_option.match "--no-long"
# => nil

这也非常适合。

现在结合起来,问题就开始了:

/#{long_option} #{value}/.match "--long 'filename.rb'"
# => nil

但是如果重新定义value而没有第一个引用的正面lookbehind,它匹配:

value2 = /
        (?<value>
          \d+
            |
          (?:
            "       # <- no positive lookbehind
            [^"]+
            (?=")
          )
            |
          (?:
            '       # <- for single quote too
            [^']+
            (?=')
          )
        )
      /x

/#{long_option} #{value2}/.match "--long 'filename.rb'"
# => #<MatchData
 "long 'filename.rb"
 long_option:"long"
 key_name:"long"
 value:"'filename.rb">

我尝试将long_option与更简单的匹配结合起来并且它有效,所以我倾向于认为它不是问题的明显的来源,因此我的问题是,例如

/#{long_option} abc/.match "--long abc"
# => #<MatchData "long abc" long_option:"long" key_name:"long">

我在脑海中经历了这场比赛,试验和错误的模式略有不同,我真的被卡住了。任何帮助或见解将不胜感激。

Ruby版本是1.9。

1 个答案:

答案 0 :(得分:0)

/#{long_option} #{value}/将不会像您预期的那样匹配双引号或单引号中的字符串,因为正{look}'出现在value的开头,当其前面的字符是双引号或单引号时,其匹配成功。但是在/#{long_option} #{value}/中,value之前的字符是一个空格,并且由于空格字符不能同时是双引号或单引号,因此该替代匹配永远不会成功。