正则表达式重复aa,bb,cc

时间:2019-07-11 05:59:01

标签: regex ruby

我希望以下各项能够奏效(并且确实如此):

x = '"aa","bb","cc"'

x =~ /\A(".*?",){2}".*?"\Z/
#=> 0 

...但是我没想到下面两个会起作用(并且不希望它们起作用)。我故意使用?来使.*变得非贪婪:

x =~ /\A(".*?",){0}".*?"\Z/
#=> 0 

x =~ /\A(".*?",){1}".*?"\Z/
#=> 0 

我希望:行(\A)的开头,接着是"aa",,然后是"bb",(这是现在的两个匹配项,即{2}),然后是{{ 1}},以及行"cc"的结尾。

我了解为什么为什么有效,但是我想了解如何实现自己想要的目标...

在以上最后两个示例中,我希望它失败(但不是)。换句话说,我希望以下操作失败:

\Z

应该看到:x = '"aa","bb","cc","dd"' x =~ /\A(".*?",){2}".*?"\Z/ #=> 0 \A"aa""bb",然后对后续的"cc"失败(事实并非{{ 1}})。

1 个答案:

答案 0 :(得分:6)

问题是.太笼统,甚至是非贪婪的.*?也会匹配,"

'"aa","bb","cc"'.match(/\A(".*?",){1}(".*?")\Z/).captures
#=> ["\"aa\",", "\"bb\",\"cc\""]

此外,如果贪婪匹配和非贪婪匹配都需要继续到字符串末尾,则它们之间也没有区别。 /.*\Z//.*?\Z/相同。

您无法删除\Z,因此可以将.替换为[^"],以避免与"匹配。

three = '"aa","bb","cc"'
four = '"aa","bb","cc","dd"'

pattern = /\A("[^"]*",){2}"[^"]*"\Z/

(three =~ pattern) && (four !~ pattern)
#=> true

regex on debuggex

如果正则表达式变得太不可读,则可以尝试将您的文本解析为JSON数组:

require 'json'
three = '"aa","bb","cc"'
four = '"aa","bb","cc","dd"'

def has_n_strings?(text, n)
  words = JSON.parse("[#{text}]")
  words.all?(String) && words.size == n
end

puts has_n_strings?(three, 3)
# true
puts has_n_strings?(three, 4)
# false
puts has_n_strings?(four, 4)
# true
puts has_n_strings?(four, 3)
# false