先週の水曜日の続きである。
先週の水曜日、第573回はPerl正規表現の文字クラスと、Unicodeの関係について、ひらがなを題材にとって述べた。
イジハピ! : 【第573回】UnicodeプロパティとPerl正規表現(その1:文字クラスとひらがなの範囲)
今日はPerlの正規表現文字クラスの簡略表記、\d、\w、\sについて考える。
ただし、ものかのさんのブログに完璧かつ簡潔に書かれているので、お急ぎの方はそっちを見るといいだろう。
ものかの » 正規表現の略記法 \d と \s と \w
じゃあなぜ完璧なブログがあるのにそれをダラダラ書き伸ばすのかという疑問が生じるが、それはこのブログでしょっちゅうやっていることであるから気にしないことにする。

先週の水曜日、第573回はPerl正規表現の文字クラスと、Unicodeの関係について、ひらがなを題材にとって述べた。
イジハピ! : 【第573回】UnicodeプロパティとPerl正規表現(その1:文字クラスとひらがなの範囲)
今日はPerlの正規表現文字クラスの簡略表記、\d、\w、\sについて考える。
ただし、ものかのさんのブログに完璧かつ簡潔に書かれているので、お急ぎの方はそっちを見るといいだろう。
ものかの » 正規表現の略記法 \d と \s と \w
じゃあなぜ完璧なブログがあるのにそれをダラダラ書き伸ばすのかという疑問が生じるが、それはこのブログでしょっちゅうやっていることであるから気にしないことにする。

先日Perlの正規表現文字クラスについて書いたが、これらの文字クラスには略記法がある。
以下の通りである。
Table 5.8. Classic Character Classes
Symbol Meaning As Bytes As utf8
\d Digit [0-9] \p{IsDigit}
\D Nondigit [^0-9] \P{IsDigit}
\s Whitespace [ \t\n\r\f] \p{IsSpace}
\S Nonwhitespace [^ \t\n\r\f] \P{IsSpace}
\w Word character [a-zA-Z0-9_] \p{IsWord}
\W Non-(word character) [^a-zA-Z0-9_] \P{IsWord}
Character Classes (Programming Perl)の表5.8より
おおまかに言うと、
・\dが数字(digit 桁)であって、\Dがそれ以外
・\sが空白(space スペース)であって、\Sがそれ以外
・\wが英数字(word)であって、\Wがそれ以外
という意味だったが、no utf8状態(上の表の「As Bytes」)とuse utf8状態(同じく「As utf8」)で指す範囲が全然違う。
(※\wにアンダースコア_が入るのに注意)
\dはAs Bytes状態だと[0-9]で、数字1桁である。
これは明快である。
(Perlでは無視される桁区切り文字としてアンダースコア(_)を入れることが出来る(1,000,000を1_000_000と書ける)が、_は\dに入らないので注意)
しかしAs utf8状態だと\p{IsDigit}と書いている。
これは概ねPOSIX文字クラスに近く、該当するUnicodeプロパティは以下のとおりである。
Table 5.9. Composite Unicode Properties
Property Equivalent
IsASCII [\x00-\x7f]
IsAlnum [\p{IsLl}\p{IsLu}\p{IsLt}\p{IsLo}\p{IsNd}]
IsAlpha [\p{IsLl}\p{IsLu}\p{IsLt}\p{IsLo}]
IsCntrl \p{IsC}
IsDigit \p{Nd}
IsGraph [^\pC\p{IsSpace}]
IsLower \p{IsLl}
IsPrint \P{IsC}
IsPunct \p{IsP}
IsSpace [\t\n\f\r\p{IsZ}]
IsUpper [\p{IsLu}\p{IsLt}]
IsWord [_\p{IsLl}\p{IsLu}\p{IsLt}\p{IsLo}\p{IsNd}]
IsXDigit [0-9a-fA-F]
Character Classes (Programming Perl)の表5.9より
IsDigitは\p{Nd}に等しい。
NdというGeneral_Propertyを持っているUnicodeである。
(ちなみに\dの否定である\D(数字以外の1文字)は、\P{IsDigit}すなわち\P{Nd}と等値である。)
この集合に含まれる文字はUnicodeのバージョンによって異なる。
また、PerlのバージョンによってサポートするUnicodeのバージョンが異なる。
このブログを書いている2014年04月05日においてPerlのバージョンは5.18.2である。
The Perl Programming Language - www.perl.org
Perlは5.18.0でUnicode 6.2をサポートしている。
perldelta - search.cpan.org
DerivedNumericType.txtというテキストの一番下に、Ndというプロパティの文字の一覧が乗っている。
DerivedNumericType.txt
以下に抜粋を示す。
後ろに//をはさんでコメントを付す。
0030..0039 ; Decimal # Nd [10] DIGIT ZERO..DIGIT NINE // ASCIIの0〜9
0660..0669 ; Decimal # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE // アラビア・インド語の0〜9
…
FF10..FF19 ; Decimal # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE // 全角の0〜9
…
1D7CE..1D7FF ; Decimal # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE // 数学的な太字のゼロ〜数学的な等幅の9
# Total code points: 460
460個ある。
最後のU+1D7CEだけが50個あって、それ以外はゼロから9まで10個ずつ、41言語で410個である。
話が長くなったが、use utf8状態で\dを使うと、全世界言語におけるゼロ〜9にマッチするのである。
便利だろうか。
たとえそういう用事に使いたいことが年に1回ぐらいあるとしても、多くの場合は不便だと思う。
ではuse utf8しなければいいのかというと、ASCII以外のスクリプトが入ってくると使い物にならない(ひらがなや漢字が1文字ずつ処理できない)ので、使わないわけにはいかない。
ところが!
Perl 5.14以降の機能としては、m//(マッチ)演算子やs///(置換、substitute)演算子の修飾子(modifier)に/a(ASCIIの略か?)を渡すことで、no utf8の\dに直せる。
perlre - perldoc.perl.org(Modifiers)
\sは\p{IsSpace}に等しく、以下に掲げる26文字である。
0009..000D ; White_Space # Cc [5]..
0020 ; White_Space # Zs SPACE
0085 ; White_Space # Cc
00A0 ; White_Space # Zs NO-BREAK SPACE
1680 ; White_Space # Zs OGHAM SPACE MARK
180E ; White_Space # Zs MONGOLIAN VOWEL SEPARATOR
2000..200A ; White_Space # Zs [11] EN QUAD..HAIR SPACE
2028 ; White_Space # Zl LINE SEPARATOR
2029 ; White_Space # Zp PARAGRAPH SEPARATOR
202F ; White_Space # Zs NARROW NO-BREAK SPACE
205F ; White_Space # Zs MEDIUM MATHEMATICAL SPACE
3000 ; White_Space # Zs IDEOGRAPHIC SPACE // 全角スペース
# Total code points: 26
DerivedGeneralCategory.txt
U+3000 はIDEOGRAPHIC SPACEと書いており、直訳すると「表意文字の空白」という意味だがどういうことだろうか。
これは全角スペース「 」である。
ということで、不便だが、m//やs///で/a修飾子を使うとno utf8の\sになる。
これがすごくて、IsWord=[_\p{IsLl}\p{IsLu}\p{IsLt}\p{IsLo}\p{IsNd}]ということで、だいたい全部のLetter(アルファベット、ひらがな、カタカナその他)が全部入る。
404 Blog Not Found:perl - Unicode「'あ'はAlphabetですが、何か?」
これ使う用ないと思う。
範囲が膨大だ。
でもまあ、/a修飾子を使ってm//aあるいはs///aと書くと、use utf8であってもno utf8の\wになる。
ということで、Perlの正規表現がUnicodeを取り入れてめちゃめちゃ使いにくなったと長い間困っていたが、5.14で/a修飾子があるから別に問題なくなった。
あと「しゅうしょくし」で変換すると就職誌になるのは注意。
以下の通りである。
Table 5.8. Classic Character Classes
Symbol Meaning As Bytes As utf8
\d Digit [0-9] \p{IsDigit}
\D Nondigit [^0-9] \P{IsDigit}
\s Whitespace [ \t\n\r\f] \p{IsSpace}
\S Nonwhitespace [^ \t\n\r\f] \P{IsSpace}
\w Word character [a-zA-Z0-9_] \p{IsWord}
\W Non-(word character) [^a-zA-Z0-9_] \P{IsWord}
Character Classes (Programming Perl)の表5.8より
おおまかに言うと、
・\dが数字(digit 桁)であって、\Dがそれ以外
・\sが空白(space スペース)であって、\Sがそれ以外
・\wが英数字(word)であって、\Wがそれ以外
という意味だったが、no utf8状態(上の表の「As Bytes」)とuse utf8状態(同じく「As utf8」)で指す範囲が全然違う。
(※\wにアンダースコア_が入るのに注意)
\d(数字)
\dはAs Bytes状態だと[0-9]で、数字1桁である。
これは明快である。
(Perlでは無視される桁区切り文字としてアンダースコア(_)を入れることが出来る(1,000,000を1_000_000と書ける)が、_は\dに入らないので注意)
しかしAs utf8状態だと\p{IsDigit}と書いている。
これは概ねPOSIX文字クラスに近く、該当するUnicodeプロパティは以下のとおりである。
Table 5.9. Composite Unicode Properties
Property Equivalent
IsASCII [\x00-\x7f]
IsAlnum [\p{IsLl}\p{IsLu}\p{IsLt}\p{IsLo}\p{IsNd}]
IsAlpha [\p{IsLl}\p{IsLu}\p{IsLt}\p{IsLo}]
IsCntrl \p{IsC}
IsDigit \p{Nd}
IsGraph [^\pC\p{IsSpace}]
IsLower \p{IsLl}
IsPrint \P{IsC}
IsPunct \p{IsP}
IsSpace [\t\n\f\r\p{IsZ}]
IsUpper [\p{IsLu}\p{IsLt}]
IsWord [_\p{IsLl}\p{IsLu}\p{IsLt}\p{IsLo}\p{IsNd}]
IsXDigit [0-9a-fA-F]
Character Classes (Programming Perl)の表5.9より
IsDigitは\p{Nd}に等しい。
NdというGeneral_Propertyを持っているUnicodeである。
(ちなみに\dの否定である\D(数字以外の1文字)は、\P{IsDigit}すなわち\P{Nd}と等値である。)
この集合に含まれる文字はUnicodeのバージョンによって異なる。
また、PerlのバージョンによってサポートするUnicodeのバージョンが異なる。
このブログを書いている2014年04月05日においてPerlのバージョンは5.18.2である。
The Perl Programming Language - www.perl.org
Perlは5.18.0でUnicode 6.2をサポートしている。
perldelta - search.cpan.org
DerivedNumericType.txtというテキストの一番下に、Ndというプロパティの文字の一覧が乗っている。
DerivedNumericType.txt
以下に抜粋を示す。
後ろに//をはさんでコメントを付す。
0030..0039 ; Decimal # Nd [10] DIGIT ZERO..DIGIT NINE // ASCIIの0〜9
0660..0669 ; Decimal # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE // アラビア・インド語の0〜9
…
FF10..FF19 ; Decimal # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE // 全角の0〜9
…
1D7CE..1D7FF ; Decimal # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE // 数学的な太字のゼロ〜数学的な等幅の9
# Total code points: 460
460個ある。
最後のU+1D7CEだけが50個あって、それ以外はゼロから9まで10個ずつ、41言語で410個である。
話が長くなったが、use utf8状態で\dを使うと、全世界言語におけるゼロ〜9にマッチするのである。
便利だろうか。
たとえそういう用事に使いたいことが年に1回ぐらいあるとしても、多くの場合は不便だと思う。
ではuse utf8しなければいいのかというと、ASCII以外のスクリプトが入ってくると使い物にならない(ひらがなや漢字が1文字ずつ処理できない)ので、使わないわけにはいかない。
ところが!
Perl 5.14以降の機能としては、m//(マッチ)演算子やs///(置換、substitute)演算子の修飾子(modifier)に/a(ASCIIの略か?)を渡すことで、no utf8の\dに直せる。
perlre - perldoc.perl.org(Modifiers)
use utf8;
…
/\d/; # /p{IsDigit}/;
…
/\d/a; # /[0-9]/と等値
\s(空白)
\sは\p{IsSpace}に等しく、以下に掲げる26文字である。
0009..000D ; White_Space # Cc [5]
0020 ; White_Space # Zs SPACE
0085 ; White_Space # Cc
00A0 ; White_Space # Zs NO-BREAK SPACE
1680 ; White_Space # Zs OGHAM SPACE MARK
180E ; White_Space # Zs MONGOLIAN VOWEL SEPARATOR
2000..200A ; White_Space # Zs [11] EN QUAD..HAIR SPACE
2028 ; White_Space # Zl LINE SEPARATOR
2029 ; White_Space # Zp PARAGRAPH SEPARATOR
202F ; White_Space # Zs NARROW NO-BREAK SPACE
205F ; White_Space # Zs MEDIUM MATHEMATICAL SPACE
3000 ; White_Space # Zs IDEOGRAPHIC SPACE // 全角スペース
# Total code points: 26
DerivedGeneralCategory.txt
U+3000 はIDEOGRAPHIC SPACEと書いており、直訳すると「表意文字の空白」という意味だがどういうことだろうか。
これは全角スペース「 」である。
ということで、不便だが、m//やs///で/a修飾子を使うとno utf8の\sになる。
\w(英数字)
これがすごくて、IsWord=[_\p{IsLl}\p{IsLu}\p{IsLt}\p{IsLo}\p{IsNd}]ということで、だいたい全部のLetter(アルファベット、ひらがな、カタカナその他)が全部入る。
404 Blog Not Found:perl - Unicode「'あ'はAlphabetですが、何か?」
これ使う用ないと思う。
範囲が膨大だ。
でもまあ、/a修飾子を使ってm//aあるいはs///aと書くと、use utf8であってもno utf8の\wになる。
ということで、Perlの正規表現がUnicodeを取り入れてめちゃめちゃ使いにくなったと長い間困っていたが、5.14で/a修飾子があるから別に問題なくなった。
あと「しゅうしょくし」で変換すると就職誌になるのは注意。