0

我无法在我的正则表达式中指定“下一个字符不应来自这组字符”。我有

TOKENS = [":", ".", "'"]
"01:39\t" =~  /\b0\d[#{Regexp.union(TOKENS)}]\d\d^#{Regexp.union(TOKENS)}/
 #=> nil

由于"\t"不是我的TOKENS数组的一部分,我认为上面应该匹配,但事实并非如此。如何调整我的正则表达式,特别是这部分

^#{Regexp.union(TOKENS)}

说字符不应该是这个数组的一部分?

4

2 回答 2

0

你的/\b0\d[#{Regexp.union(TOKENS)}]\d\d^#{Regexp.union(TOKENS)}/模式最终看起来像

/(?-mix:\b0\d[(?-mix::|\.|')]\d\d^(?-mix::|\.|'))/
             ^^^^^^^^^^^^^^^^    ^^^^^^^^^^^^^^^

在这里,正则表达式对象是一个修饰符组,它禁用了多行、不区分大小写和自由间距模式。最后一个^是行锚的开始,它单独破坏了整个正则表达式,将其变成了一个永远不会匹配任何字符串的模式。

#{Regexp.union(TOKENS)} 用字符类括号包装是不够的[...],您需要使用该.source属性来摆脱,(?-mix:...)因为您不想否定m, i,x等。但是,您不能使用Regexp.union,因为它会添加|char 和 inside一个字符类,它被视为文字字符(因此,您还将否定管道)。

您应该定义分隔符序列TOKENS.join().gsub(/[\]\[\^\\-]/, '\\\\\\&')以转义应该在正则表达式字符类中转义的所有字符,然后放在字符类方括号之间。

红宝石演示:

TOKENS = [":", ".", "'", "]"]
sep_rx = TOKENS.join().gsub(/[\]\[\^\\-]/, '\\\\\\&')
puts sep_rx
# => :.'\]
rx = /\b0\d[#{sep_rx}]\d\d[^#{sep_rx}]/
puts rx.source
# => \b0\d[:.'\]]\d\d[^:.'\]]
puts "01:39\t" =~  rx
# => 0

查看Rubular 演示

请注意,.gsub(/[\]\[\^\\-]/, '\\\\\\&')匹配], [,^\and-在它们前面添加一个反斜杠。前 4 个反斜杠在'\\\\\\&'替换模式中定义了一个文字反斜杠,\\&代表整个匹配

于 2017-11-07T07:52:28.947 回答
0

您需要在正则表达式的“非”部分周围加上括号。

>> TOKENS = [":", ".", "'"]
>> regex = /\b0\d[#{Regexp.union(TOKENS)}]\d\d^#{Regexp.union(TOKENS)}/
>> "01:39\t" =~ regex
#=> nil

然而:

>> regex = /\b0\d[#{Regexp.union(TOKENS)}]\d\d[^#{Regexp.union(TOKENS)}]/
# Add brackets                            here^                and here^
>> "01:39\t" =~ regex
#=> 0
于 2017-11-07T04:24:42.587 回答