正規表現の文字クラスの略記法 \d と \s と \w がいつのまにかアレレなことになっていたのでメモ。(1
- Perl 5.8 以降で正規表現を使うには use utf8 が必須。
- use utf8 では \d と \s と \w の文字クラスの内容が Unicode のカテゴリーに基づいている。
- InDesign(Boost)も同様。
PCRE や Ruby は変わりなし。(2- 参考資料:perldoc の perlrecharclass
- 参考資料:Programming Perl の 5.4. Character Classes
ちょっと詳しく見ていきます。 *以降、Perl = use utf8 の Perl
\d
ほとんど全ての人が [0-9] の10文字として使っていますが、Perl では \p{Nd} です。ただし、Perlのバージョンによって(対応しているUnicodeバージョンが異なるので)文字クラスの内容が異なります。全角数字もマッチします。
- OS X 10.5.8/Perl 5.8.8: Unicode 4.1 の 270 文字
- OS X 10.6.8/Perl 5.10.0: Unicode 5.0 の 290 文字
- OS X 10.7.1/Perl 5.12.3: Unicode 5.2 の 410 文字 *リンク先の 411 文字の記載は誤り
\s
ほとんど全ての人が [ \t\n\r\f] の5文字として使っていますが、Perl では [\t\n\r\f\p{Z}\x{000b}\x{0085}] です。Unicode 3.0 から \p{Z} は変わっていないので、今のところ26文字です。全角スペースもマッチします。
\w
ほとんど全ての人が [_a-zA-Z0-9] の63文字として使っていますが、Perl では [_\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}] です。当然バージョンごとに文字クラスの内容は異なります。あまりに文字数が多すぎて、全角文字もマッチしまくるので、もはやこれを使う意味がなくなっているような…
感想
正規表現での文字クラスの指定は、それがどの文字を指しているのかを書く側が正確に把握していなければいけません。上記の3つの略記法は対応するUnicodeのバージョンによって文字クラスが大きく変わります。とくに \w はその文字数も変化も膨大で、とても把握しきれるものではありません。
そもそもUnicodeのカテゴリーやブロックやスクリプトには、正規表現での利用を超えた意図が反映されています。例えばカタカナのスクリプトには合字などが含まれます。よほどの特殊な用途でない限り、Unicodeの規格に依存した文字クラスの指定はするべきではないと考えます。
InDesign では…
InDesignがUnicodeのカテゴリー準拠になったのはCS4から。それ以降ずっと \d は Unicode 5.1 の Nd で 370 文字。
追記
\b もそうでした。
追記
InDesign の正規表現は CC 2018(v13)までずーっと Unicode 5.1 準拠だったのですけど、CC 2019(v14)で Unicode 9.0 準拠になっていました。どういうことかというと、略記法でマッチする文字が増えているってことです。ちなみに、\d は Unicode 9.0 の Nd なので 580 文字にマッチします。
Tweet
Ruby のは -Ku と # coding: utf-8 の違いではなく,Ruby 1.8 系と Ruby 1.9 系の違いではないでしょうか。
ご指摘を受けて、念入りに調べてみました。OS X 10.5.8 の Ruby 1.8.7 です。
—-
#!/usr/bin/ruby -Ku
puts “123/123/あいう/,./。、”.gsub(/\w/, “*”)
結果 –> ***/***/***/,./**
—-
これはおかしいですね。全角句読点にマッチしちゃってます。
—-
#!/usr/bin/ruby
# coding: utf-8
puts “123/123/あいう/,./。、”.gsub(/\w/, “*”)
結果 –> ***/123/あいう/,./。、
—-
こっちは [_a-zA-Z0-9] 同等のようです。
Ruby 1.9 系ではどのような結果になるんでしょ?
まず、ruby 1.8系でエンコーディングを指定するMagic commentを入れても単なるコメントとして扱われます。
1.8系で-Kオブション(または$KCODE)を指定しないと、ASCIIでの処理が前提になります。
1.9系では-Kオブションではなく、エンコーディングはMagic commentで指定します。
このへんが詳しいかと思います。
http://jp.rubyist.net/magazine/?0025-Ruby19_m17n
ちなみに1.9系だとこんな感じになるはずです。
$ irb19
>> # coding: utf-8
?> puts “123/123/あいう/,./。、”.gsub(/\w/, “*”)
***/123/あいう/,./。、
1.8系で -Ku も Magic comment もなしでやってみました。
あ、UTF-8でファイル保存してます(BOMなし)。
$ ruby test.rb
—-
#!/usr/bin/ruby
puts “123/123/あいう/,./。、”.gsub(/\w/, “*”)
結果 –> ***/123/あいう/,./。、
—-
テキストエンコーディングを UTF-8 に判定して実行してるっぽい…?
Magic comment の有無はたしかに無関係ですね。
5.5 さん、せうぞーさん、ありがとうございました!!
(-Ku の \w が句読点にマッチするのが謎…笑)
Ruby 1.8 では,$KCODE の値によって gsub などの動作が変わります。
-Ku を付けると $KCODE の値が “UTF8″ になります。
$KCODE=”UTF8″ とか $KCODE=”u” のように直接代入しても同じ結果になります。
※Ruby 1.9 には $KCODE はありません。
さて,何もしなければ,$KCODE の値は “NONE” です。
この場合,文字列を単なるバイト列として扱います。
したがって,全角の “1” は EF BC 91 という三文字と解釈されるので \w にマッチしないんです。
5.5 さん、明解な説明、ありがとうございます!
すばらしいポストありがとうございます!
Perlだと最近(5.14からだから最近でもないか)m//に/a修飾子というのが出来て、これを使うと\w、\s、\dがno utf8状態になって便利です!
ふかざわさん、ご報告ありがとうございます!
perldoc の perlrecharclass に「/a modifier」が追記されているのを確認しました!
OSXの場合は10.9 がデフォルトで 5.16 なので使えますね~♪