我希望以下各项能够奏效(并且确实如此):
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}})。
答案 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
如果正则表达式变得太不可读,则可以尝试将您的文本解析为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