Сканирование номеров Юникода в строке с помощью \d

Согласно документации Oniguruma, \d тип символов соответствует:

десятичная цифра
Unicode: General_Category - Decimal_Number

Тем не менее, сканирование для \d в строке со всеми символами Decimal_Number совпадают только латинские цифры 0-9:

#encoding: utf-8
require 'open-uri'
html = open("http://www.fileformat.info/info/unicode/category/Nd/list.htm").read
digits = html.scan(/U\+([\da-f]{4})/i).flatten.map{ |s| s.to_i(16) }.pack('U*')

puts digits.encoding, digits
#=> UTF-8
#=> 0123456789٠١٢٣٤٥٦٧٨٩۰۱۲۳۴۵۶۷۸۹߀߁߂߃߄߅߆߇߈߉०१२३४५६७८९০১২৩৪৫৬৭৮৯੦੧੨…

p RUBY_DESCRIPTION, digits.scan(/\d/)
#=> "ruby 1.9.2p180 (2011-02-18) [i386-mingw32]"
#=> ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]

Я неправильно читаю документацию? Почему не \d соответствуют другим номерам Unicode, и / или есть ли способ сделать это?

3 ответа

Решение

Отмеченный Брайаном Кэндлером на ruby-talk:

  • \w соответствует только буквам и цифрам ASCII, а [[:alpha:]] соответствует полному набору букв Unicode.
  • \d соответствует только цифрам ASCII, а [[:digit:]] соответствует полному набору номеров Unicode.

Таким образом, поведение является "последовательным", и у нас есть простой обходной путь для номеров Unicode. Чтение на \w в том же документе Онигурума мы видим текст:

\w  word character  
    Not Unicode: alphanumeric, "_" and multibyte char.  
    Unicode: General_Category -- (Letter|Mark|Number|Connector_Punctuation)

В свете реального поведения Ruby и вышеприведенного текста "Not Unicode" может показаться, что в документации описываются два режима - режим Unicode и режим Not Unicode - и что Ruby работает в режиме Not Unicode.

Это объясняет, почему \d не соответствует полному набору Unicode: хотя документация Oniguruma не в состоянии точно описать то, что сопоставляется в режиме не Unicode, теперь мы знаем, что поведение, задокументированное как "Unicode", не ожидается.

p "abç".scan(/\w/), "abç".scan(/[[:alpha:]]/)
#=> ["a", "b"]
#=> ["a", "b", "\u00E7"]

Читателю оставлено упражнение, чтобы узнать, как (если это вообще возможно) включить режим Unicode в регулярных выражениях Ruby, как /u флаг (например, /\w/u) не делает этого. (Возможно, нужно перекомпилировать Ruby со специальным флагом для Oniguruma.)

Обновление: может показаться, что документ Oniguruma, на который я ссылаюсь, не является точным для Ruby 1.9. Смотрите обсуждение этого билета, включая следующие посты:

[Yui NARUSE] "RE.txt для оригинального Oniguruma, а не для регулярного выражения Ruby 1.9. Нам может понадобиться наш собственный документ".
[Matz] "Наш Онигурума разветвлен. Оригинальный Онигурума, найденный в geocities.jp, не был изменен".

Лучший справочник: Вот официальная документация по синтаксису регулярных выражений в Ruby 1.9:
https://github.com/ruby/ruby/blob/trunk/doc/re.rdoc

Попробуйте использовать символьный класс Unicode \p{N} вместо. Это соответствует всем цифрам Unicode. Не знаю почему \d не работает

\d будет соответствовать только для ASCII номеров по умолчанию. Вы можете вручную включить сопоставление Юникода в регулярном выражении, используя (нелогично) (?u) синтаксис:

"".match(/(?u)\d/) # => #<MatchData "">

Кроме того, вы можете использовать стиль "posix" или "свойство unicode" в своем регулярном выражении, которое не требует, чтобы вы вручную включали сопоставление Unicode:

/[[:digit:]]/ # posix style
/\p{Nd}/ # unicode property/category style

Более подробную информацию о том, как выполнить расширенное сопоставление символов Unicode в Ruby, можно найти в этом сообщении в блоге: http://idiosyncratic-ruby.com/30-regex-with-class.html

Другие вопросы по тегам