多字节字符是否会干扰正则表达式中的终结字符?
有了这个正则表达式:
regex1 = /\z/
以下字符串匹配:
"hello" =~ regex1 # => 5 "こんにちは" =~ regex1 # => 5
但是这些正则表达式:
regex2 = /#$/?\z/ regex3 = /\n?\z/
他们表现出差异:
"hello" =~ regex2 # => 5 "hello" =~ regex3 # => 5 "こんにちは" =~ regex2 # => nil "こんにちは" =~ regex3 # => nil
什么是干扰? 字符串编码是UTF-8,操作系统是Linux(即$/
是"\n"
)。 多字节字符是否会干扰$/
? 怎么样?
您报告的问题肯定是RUBY_VERSION #=> "2.0.0"
的Regexp
的错误,但在编码允许多字节字符(例如__ENCODING__ #=> #
时已存在于之前的1.9中
不依赖于Linux,它也可能在OSX和Windows中重现相同的行为。
在修复bug 8210时,我们可以通过隔离和理解问题发生的案例来帮助解决问题。 当适用于特定情况时,这对任何变通方法都很有用。
我明白问题发生在:
- 在字符串结尾之前搜索一些内容
\z
。 - 并且字符串的最后一个字符是多字节的 。
- 并且之前的搜索使用零个或一个模式
?
- 但搜索的零或一个字符的数量小于最后一个字符的字节数。
该错误可能是由正常表达式引擎实际检查的字节数和字符数之间的误解造成的。
一些例子可能会有所帮助:
测试1:最后一个字符:“は”是3个字节:
s = "んにちは"
在字符串结束前测试零或一个ん[3字节]:
s =~ /ん?\z/u #=> 4" # OK it works 3 == 3
当我们尝试ç[2字节]时
s =~ /ç?\z/u #=> nil # KO: BUG when 3 > 2 s =~ /x?ç?\z/u #=> 4 # OK it works 3 == ( 1+2 )
当测试零或一个\ n [1字节]时
s =~ /\n?\z/u #=> nil" # KO: BUG when 3 > 1 s =~ /\n?\n?\z/u #=> nil" # KO: BUG when 3 > 2 s =~ /\n?\n?\n?\z/u #=> 4" # OK it works 3 == ( 1+1+1)
通过TEST1的结果,我们可以断言: 如果字符串的最后一个多字节字符是3个字节,那么“零或一个之前”测试仅在我们之前测试至少3个字节(不是3个字符)时起作用。
测试2:最后一个字符“ç”是2个字节
s = "in French there is the ç"
检查零或一个ん[3字节]“
s =~ /ん?\z/u #=> 24 # OK 2 <= 3
检查零或一个é[2字节]
s =~ /é?\z/u #=> 24 # OK 2 == 2 s =~ /x?é?\z/u #=> 24 # OK 2 < (2+1)
测试零或一个\ n [1个字节]
s =~ /\n?\z/u #=> nil # KO 2 > 1 ( the BUG occurs ) s =~ /\n?\n?\z/u #=> 24 # OK 2 == (1+1) s =~ /\n?\n?\n?\z/u #=> 24 # OK 2 < (1+1+1)
通过TEST2的结果,我们可以断言: 如果字符串的最后一个多字节字符是2个字节,那么“零或一个之前”测试仅在我们之前检查至少2个字节(不是2个字符)时起作用。
当多字节字符不在字符串的末尾时,我发现它可以正常工作。
公开要点,我的测试代码在这里可用
在Ruby主干中 ,这个问题现在已被接受为bug。 希望它会被修复。
更新:Ruby trunk中发布了两个补丁。