16

使用这个正则表达式:

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(即$/is "\n")。多字节字符是否干扰$/?如何?

4

2 回答 2

3

当编码允许多字节字符时,您报告的问题绝对是 1.9 的错误,RegexpRUBY_VERSION #=> "2.0.0"在以前的 1.9 中已经存在,例如__ENCODING__ #=> #<Encoding:UTF-8>

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

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

我了解在以下情况下会出现问题:

  • 在字符串结尾 之前搜索某些内容\z
  • 并且字符串的最后一个字符是multi-byte
  • 而之前的搜索使用零个或一个模式?
  • 但搜索到的零或一个字符的数量少于最后一个字符的字节数。

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

几个例子可能会有所帮助:

测试 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 个字符)时才有效。

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

带有我的测试代码的公共要点可在此处获得

于 2013-04-08T18:03:46.047 回答
1

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

更新:在 Ruby 主干中发布了两个补丁。

于 2013-04-09T02:26:01.103 回答