多字节字符是否会干扰正则表达式中的结束字符?

时间:2013-04-03 05:55:42

标签: ruby regex encoding multibyte ruby-2.0

这个正则表达式:

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")。多字节字符是否会干扰$/?怎么样?

2 个答案:

答案 0 :(得分:3)

您报告的问题绝对是Regexp RUBY_VERSION #=> "2.0.0"的错误,但在编码允许多字节字符(例如__ENCODING__ #=> #<Encoding:UTF-8>

不依赖于Linux,也可以在OSX和Windows中重现相同的行为。

在修复bug 8210的同时,我们可以通过隔离了解发生问题的案例来提供帮助。 当适用于特定情况时,这对任何解决方法也很有用。

我知道问题发生在:

  • 字符串结尾 \z之前搜索内容。
  • ,字符串的最后一个字符是多字节
  • 并且之前的搜索使用零或一个模式?
  • 但搜索的零或一个字符数小于最后一个字符的字节数

该错误可能是由于字节数与正则表达式引擎实际检查的字符数之间的误解造成的。

一些例子可能有所帮助:

测试1:最后一个字符:“は”是3个字节:

s = "んにちは"

在字符串结束前测试零或一个ん[3字节]:

s =~ /ん?\z/u   #=> 4"       # OK it works 3 == 3

当我们尝试使用ç[2 bytes]

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个字节)时起作用字符)之前。

TEST 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个字节)时起作用字符)之前。

当多字节字符不在字符串的末尾时,我发现它可以正常工作。

public gist with my test code available here

答案 1 :(得分:1)

Ruby trunk中,此问题现在已被接受为错误。希望它会被修复。

更新:Ruby trunk中发布了两个补丁。