Ответ 1
В Ruby trunk проблема теперь была принята как ошибка. Надеюсь, это будет исправлено.
Обновление: в Ruby trunk размещены два патча.
С помощью этого регулярного выражения:
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 trunk проблема теперь была принята как ошибка. Надеюсь, это будет исправлено.
Обновление: в Ruby trunk размещены два патча.
Проблема, о которой вы сообщили, определенно является ошибкой Regexp
of RUBY_VERSION #=> "2.0.0"
, но уже существующей в предыдущих версиях 1.9, когда кодировка разрешает многобайтовые символы, такие как __ENCODING__ #=> #<Encoding:UTF-8>
Не зависит от Linux, возможно воспроизвести одно и то же поведение в OSX и Windows.
В то время как ошибка 8210 будет исправлена, мы можем помочь, изолируя и понимая случаи, в которых возникает проблема. Это также может быть полезно для любого способа обхода, если применимо к конкретным случаям.
Я понимаю, что проблема возникает, когда:
\z
.?
Ошибка может быть вызвана недоразумениями между количеством байтов и числом символов, которое фактически проверяется механизмом регулярных выражений.
Несколько примеров могут помочь:
s = "んにちは"
s =~ /ん?\z/u #=> 4" # OK it works 3 == 3
s =~ /ç?\z/u #=> nil # KO: BUG when 3 > 2
s =~ /x?ç?\z/u #=> 4 # OK it works 3 == ( 1+2 )
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 байтам, то тест "zero или one before" работает только тогда, когда мы тестируем как минимум 3 байта (не 3 символа) до.
s = "in French there is the ç"
s =~ /ん?\z/u #=> 24 # OK 2 <= 3
s =~ /é?\z/u #=> 24 # OK 2 == 2
s =~ /x?é?\z/u #=> 24 # OK 2 < (2+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 символа) до.
Если многобайтовый символ не находится в конце строки, я нашел, что он работает правильно.