使用\ d扫描字符串中的Unicode数字

Phr*_*ogz 8 ruby regex unicode character-properties

根据Oniguruma文档,\d字符类型匹配:

decimal digit char
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"]
Run Code Online (Sandbox Code Playgroud)

我误读了文档吗?为什么不\d匹配其他Unicode数字,和/或有没有办法让它这样做?

Phr*_*ogz 2

Brian Candler 在 ruby​​-talk 上指出:

\n\n
    \n
  • \\w只匹配 ASCII 字母和数字,而[[:alpha:]]匹配全套 Unicode 字母。
  • \n
  • \\d只匹配 ASCII 数字,而[[:digit:]]匹配全套 Unicode 数字。
  • \n
\n\n

因此,行为是“一致的”,并且我们有一个针对 Unicode 数字的简单解决方法。阅读\\w一个 Oniguruma 文档,我们会看到以下文本:

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

根据 Ruby 的实际行为和上面的“Not Unicode”文本,文档似乎描述了两种模式 - Unicode 模式和 Not Unicode 模式 - 并且 Ruby 正在 Not Unicode 模式下运行。

\n\n

这可以解释为什么\\d不匹配完整的 Unicode 集:尽管 Oniguruma 文档未能准确描述在非 Unicode 模式下匹配的内容,但我们现在知道记录为“Unicode”的行为是不可预期的。

\n\n
p "ab\xc3\xa7".scan(/\\w/), "ab\xc3\xa7".scan(/[[:alpha:]]/)\n#=> ["a", "b"]\n#=> ["a", "b", "\\u00E7"]\n
Run Code Online (Sandbox Code Playgroud)\n\n

留给读者的练习是发现如何(如果有的话)在 Ruby 正则表达式中启用 Unicode 模式,因为标志/u(例如/\\w/u)不会这样做。(也许 Ruby 必须使用 Oniguruma 的特殊标志重新编译。)

\n\n

更新:看来我链接到的 Oniguruma 文档对于 Ruby 1.9 来说并不准确。请参阅此票证讨论,包括以下帖子:

\n\n
\n

[Yui NARUSE]“RE.txt 适用于原始 Oniguruma,不适用于 Ruby 1.9\ 的正则表达式。我们可能需要自己的文档。”
\n [Matz]“我们的 Oniguruma 是分叉的。在 geocities.jp 中发现的原始 Oniguruma 尚未更改。”

\n
\n\n

更好的参考:这是有关 Ruby 1.9 正则表达式语法的官方文档:
\n https://github.com/ruby/ruby/blob/trunk/doc/re.rdoc

\n

  • @tchrist我并不是说你错了,只是你所讨论的内容与这个问题完全无关。看起来您正在使用这个问题来发泄您对 Ruby 对 Unicode 处理不当(仅限于或不限于正则表达式)的不满。最后: `"Ⓜ".scan(/[[:alpha:]]/)` 正如我相信你所说的那样工作。 (2认同)