问题描述
TLDR:当禁用多行匹配时,如何让 Ruby 的正则表达式引擎从倒置字符类中排除换行符?
背景
对于我使用过的大多数正则表达式引擎,除非指定了多行修饰符,否则不可能跨行匹配。 .
运算符应该匹配除换行符之外的任何字符,并且倒置字符类 ([^x]
) 也不应该匹配换行符。例如,使用 ripgrep:
printf "a\nb\nc\nd" | rg '^a.*b.*c.*d$'
# [no output]
printf "a\nb\nc\nd" | rg '^a[^x]*b[^x]*c[^x]*d$'
# [no output]
^
和 $
运算符应该匹配任何行的开头和结尾,而不仅仅是整个字符串,如下所示:
printf "a\nb\nc\nd" | rg '^c$'
# c
使用多行选项,ripgrep 可以跨行匹配:
printf "a\nb\nc\nd" | rg --multiline --multiline-dotall '^a.*b.*c.*d$'
# a
# b
# c
# d
printf "a\nb\nc\nd" | rg --multiline --multiline-dotall '^a[^x]*b[^x]*c[^x]*d$'
# a
# b
# c
# d
Ruby 也不允许 .
匹配换行符,除非存在 m
修饰符,并且 ^
和 $
运算符可以匹配字符串中的任何行:
"a\nb\nc\nd".match(/^a.*b.*c.*d/)
# => nil
"a\nb\nc\nd".match(/^c$/)
# => #<MatchData "c">
"a\nb\nc\nd".match(/^a.*b.*c.*d/m)
# => #<MatchData "a\nb\nc\nd">
问题
然而,Ruby 的正则表达式引擎在给定倒置字符类时匹配换行符,即使没有多行修饰符。这是非常出乎意料的!
# This should return nil!
"a\nb\nc\nd".match(/^a[^x]*b[^x]*c[^x]*d$/)
# => #<MatchData "a\nb\nc\nd">
"a\nb\nc\nd".match(/^a[^x]*b[^x]*c[^x]*d$/m)
# => #<MatchData "a\nb\nc\nd">
我尝试过 Ruby 1.9.3、2.7.2 和 3.0,它们都表现出这种行为。所以这在 Ruby 中已经存在很长时间了。
问题
在为生成多行文本的内容编写规范时,我经常使用正则表达式。每当我使用倒置字符类时都必须指定 \n
对工作效率的影响非常大,并且违反了最小惊讶原则。
那么,当禁用多行匹配时,如何让 Ruby 的正则表达式引擎从倒置字符类中排除换行符?
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)