今日はUnicode時代の(use utf8を使った)Perlの正規表現について考えてみたい。
あいかわらずヌルいことしか書かないからな。
あいかわらずヌルいことしか書かないからな。
正規表現で、文字クラスというのがある。
[0-9]だと0,1,2,3,4,5,6,7,8,9というASCIIの数字のいずれか1文字にマッチする。
これは[0123456789]と等価である。
[a-zA-Z]だとASCII英数字1文字にマッチする。
これは[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]と等価である。
この-は文字コード順にインクリメントして範囲を示す機能がある。
ただし、文字クラスは、範囲に入っている文字のいずれかであるから、順番を変えても等価である。
以下の文字クラスはいずれもASCIIの数字1文字にマッチする。
[0123456789]
[9876543210]
[0-9]
[5-90-4]
ひらがな一文字であれば、[ぁ-ん]である。
さすがにちょっと端折って書くが、[ぁあぃいぅうぇえぉおかがきぎくぐけげこご…ただちぢっつづてで…わゐゑをん]と等価になる。
Unicodeで言えばU+3041〜U+3093である。
The Unicode Standard, Version 6.3 - U3040.pdf
なぜ「ぁあぃいぅう」「ががぎぎ」「っつづ」という順序になるかというと、
ファンタジー(ふぁんたじー)
不安(ふあん)
フィンランド(フィンランド)
不意打ち(ふいうち)
アボカド(アボカド)
アボガドロ数(あぼがどろすう)
たっちゃん(たっちゃん)
タツノオトシゴ(たつのおとしご)
田鶴(たづ)
という言葉を上のようなよみがな順に並べるためで、JIS X 0208でもUnicodeでもひらがなはUnicodeに同じ順に並んでいる。
(漢字の並び順は全然違う。)
UnicodeのCode ChartsにはU+3093の続きに、U+3094「ゔ」(うに濁点)、U+3095「ゕ」(小書きのか)、U+3096「ゖ」(小書きのけ)が追加されている。
だから[ぁ-ゖ]と書けば[ぁ-ん]よりも3文字だけ多いひらがなの範囲を含む文字クラスが書ける。
更にUnicodeに入っているひらがなは以下のようである。
さて、正規表現は\p{Hiragana}、\p{InHiragana}のようなUnicodeプロパティを使って見やすく書くことも出来る。
プロパティ(属性)とは、Unicodeの文字を分けるために各文字に与えられているものだ。
一般カテゴリー、スクリプト、ブロックがある。
Unicode Character Categories
perlunicode - Perl における Unicode サポート - perldoc.jp (General_Category)
「最も一般的な文字の分類方法("most usual categorization of a character")」だそうだ。
これだと、いま話題になっているひらがなはほとんどLo(繰り返し記号と濁点はLm)に入ってしまう。
逆にLo(Letter Other、その他の文字)には世界各国の文字が入っているので(下で紹介するScripts.txtで分かる)広すぎて使えない。
ということで、ひらがな1文字の正規表現の用途には使えない。
Script.txt
perlunicode - Perl における Unicode サポート - perldoc.jp (Scripts)
Scripts.txtの中では、Hiraganaは以下の範囲である。
(※Unicodeスカラー値(の範囲) ; スクリプト名 # 一般カテゴリー名 ([文字数]) Unicode文字名(の範囲) // 実際の字(本文書で追加))
U+1B001はUnicode 6.0.0で追加されたヤ行エ段の「江」由来の「え」である。
Unicode Character 'HIRAGANA LETTER ARCHAIC YE' (U+1B001)
この字については以下のWebに詳しい。
二つの「え」の話
U+1F200は「ほか」の組み文字である。
Unicode Character 'SQUARE HIRAGANA HOKA' (U+1F200)
Perlで、U+hhhhというUnicodeスカラー値をもつUnicodeは\N{U+hhhh}で書ける。
ということで、Scripts.txtに従えば、[ぁ-ゖゝゞゟ\N{U+1B001}\N{U+1F200}]の91文字がひらがなということになりそうだ。
プログラムはASCII範囲で書くことを考えれば、全部Unicodeスカラー値を使って[\N{U+3041}-\N{U+3096}\N{U+309D}-\N{U+309F}\N{U+1B001}\N{U+1F200}]と書けばいいかもしれない。
いや、そんなこと普通は書いてられないと思う。
Unicodeスクリプト名は、Perlの正規表現では\p{スクリプト名}を使って書ける。
だから、\p{Hiragana}と書けばこの91文字にマッチする。
ひらがな1文字だから\p{Hiragana}。
ハンディだ。
UAX #44: Unicode Character Database (Block)
Blocks.txt
ブロックとスクリプトは範囲が違う。Blocks.txtの中でひらがなはこのように書かれている。
U+3040、U+3097、U+3098
ただしこれらの文字は存在しない。
逆にスクリプトに入っていて、ブロックに入っていないのは以下の2文字だ。
U+1B001(ヤ行のエ)、U+1F200(「ほか」の合略文字)
これは、以下のブロックに入っている。
さて、Perl正規表現でブロックを使うときは、\p{Inブロック名}のように書く。
Hiraganaブロック([\N{U+3040}-\N{U+3090}])は\p{InHiragana}と書く。
Kana Supplement1文字は\p{InKanaSup}と書く。
Enclosed Ideographic Supplementは、\p{InEnclosedIdeographicSup}と書く。
このブロックの略記法は、以下の文書に乗っている。
perluniprops - perldoc.perl.org
スクリプトは\p{Hiragana}。ブロックは\p{InHiragana}。
もっとも、[ぁ-ゖ]でも十分なような気がする。
短くて、\p[Hiragana]よりも打ち込む手間がかからないし、視認性もバツグンである。
もっと言うと、昔ながらのJIS X 0208の範囲の[ぁ-ん]でも普通は十分な気がする。
「ゕ」とか「ゖ」みたいな、入力が面倒で、使い道もよく分からないひらがなは省いていいのではないだろうか。
「ゔ」は、最近カタカナのウ点(ヴァイオリン、ライヴなど)が復活してきていて、そのふりがなを振る必要があるのであったほうがいい気もするが、JIS X 0208の範囲に「ゔ」は入っていない。
問題は長音記号「ー」(U+30FC)である。
JIS X 0208では、ひらがな(4区)でも、カタカナ(5区)でもなく、特殊文字に入っている。
カタカナのヘとひらがなのへ、カタカナのリとひらがなのりは別の字として区別しているのだが、「ー」は形が1つしかない。
なんでだろー。
Unicodeでも、カタカナのスクリプトKatakanaには入っていない。
Script.txtによると、
ということで、Katakanaスクリプトには、長音記号U+30FC(ー。KATAKANA-HIRAGANA PROLONGED SOUND MARK)は、絶妙に入っていない。
もう1個絶妙に入っていないU+30FBは中黒(・。KATAKANA MIDDLE DOT)である。
どっちも文字名に「KATAKANA」と入っているのに、Katakanaスクリプトに入っていないのである。
なんでだろうね。
だから\p{Katakana}と書くと、「ー」にマッチしないのである。
どうしても使うなら、「・」と「ー」は入ったほうがいいので[\p{Katakana}・ー]と書くのだろうか。
でも、上のScripts.txtにあるように半角カナとか丸で囲んだカタカナなどにもマッチしてしまうので、使わないほうがいいと思う。
ブロックはどうだろうか。
Blocks.txtによると
(常識的なカタカナって何?>自分)
だから、カタカナはブロックを使って\p{InKatakana}がいいような気がする。
でも、ひらがなはスクリプトを使って\p{Hiragana}で、カタカナはブロックを使って\p{InKatakana}とかいちいち覚えているのは面倒だ。
[ァ-ヴ・ー]で十分用が足りる気もする。
っていうかいつの間にか話がカタカナに流れたが、ひらがなも「・」と「ー」が入った方がいいと思うのなら、こっちはUnicodeスクリプトHiraganaを使う場合は[\p{Hiragana}・ー]と書く。
でも見づらいから、やっぱり[ぁ-ん・ー]でいいかもしれない。
今日の結論。
ひらがな1字の正規表現は[ぁ-ん・ー]、カタカナ1字の正規表現は[ァ-ヴ・ー]がなんだかんだ言ってカンタンで実用的な気がする。
例によって無計画に書いてたらいい長さになってしまった。
以下次週!
[0-9]だと0,1,2,3,4,5,6,7,8,9というASCIIの数字のいずれか1文字にマッチする。
これは[0123456789]と等価である。
[a-zA-Z]だとASCII英数字1文字にマッチする。
これは[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]と等価である。
この-は文字コード順にインクリメントして範囲を示す機能がある。
ただし、文字クラスは、範囲に入っている文字のいずれかであるから、順番を変えても等価である。
以下の文字クラスはいずれもASCIIの数字1文字にマッチする。
[0123456789]
[9876543210]
[0-9]
[5-90-4]
ひらがな一文字であれば、[ぁ-ん]である。
さすがにちょっと端折って書くが、[ぁあぃいぅうぇえぉおかがきぎくぐけげこご…ただちぢっつづてで…わゐゑをん]と等価になる。
Unicodeで言えばU+3041〜U+3093である。
The Unicode Standard, Version 6.3 - U3040.pdf
なぜ「ぁあぃいぅう」「ががぎぎ」「っつづ」という順序になるかというと、
ファンタジー(ふぁんたじー)
不安(ふあん)
フィンランド(フィンランド)
不意打ち(ふいうち)
アボカド(アボカド)
アボガドロ数(あぼがどろすう)
たっちゃん(たっちゃん)
タツノオトシゴ(たつのおとしご)
田鶴(たづ)
という言葉を上のようなよみがな順に並べるためで、JIS X 0208でもUnicodeでもひらがなはUnicodeに同じ順に並んでいる。
(漢字の並び順は全然違う。)
UnicodeのCode ChartsにはU+3093の続きに、U+3094「ゔ」(うに濁点)、U+3095「ゕ」(小書きのか)、U+3096「ゖ」(小書きのけ)が追加されている。
だから[ぁ-ゖ]と書けば[ぁ-ん]よりも3文字だけ多いひらがなの範囲を含む文字クラスが書ける。
更にUnicodeに入っているひらがなは以下のようである。
U+3099 〓(実際には結合用の濁点) COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK(濁点つきがない文字に濁点を振るときに使う。わ+U+3099でわ゛になる(ワ゛セリンなどに使う))だから、合成用濁点、半濁点はとりあえず考えないとすると、[ぁ-ゖ]に[゛-ゟ]を加えて、[ぁ-ゖ゛-ゟ]でいいような気がする。
U+309A 〓(実際には結合用の半濁点) COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK(半濁点つきがない文字に半濁点を振るときに使う。と+U+309Aでと゜になる(アイヌ語の発音を移すときに使う))
U+309B ゛(独立した濁点) KATAKANA-HIRAGANA VOICED SOUND MARK
U+309C ゜(独立した半濁点)KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
U+309D ゝ HIRAGANA ITERATION MARK(ひらがなの繰り返し。「あゝ声なき友よ」などと使う)
U+309E ゞ HIRAGANA VOICED ITERATION MARK(ひらがなの濁点つき繰り返し。「我が心はちゞに乱れて」などと使う)
U+309F ゟ HIRAGANA DIGRAPH YORI(「より」の合略文字)
さて、正規表現は\p{Hiragana}、\p{InHiragana}のようなUnicodeプロパティを使って見やすく書くことも出来る。
プロパティ(属性)とは、Unicodeの文字を分けるために各文字に与えられているものだ。
一般カテゴリー、スクリプト、ブロックがある。
一般カテゴリー(General Categories)
UAX #44: Unicode Character DatabaseUnicode Character Categories
perlunicode - Perl における Unicode サポート - perldoc.jp (General_Category)
「最も一般的な文字の分類方法("most usual categorization of a character")」だそうだ。
これだと、いま話題になっているひらがなはほとんどLo(繰り返し記号と濁点はLm)に入ってしまう。
逆にLo(Letter Other、その他の文字)には世界各国の文字が入っているので(下で紹介するScripts.txtで分かる)広すぎて使えない。
ということで、ひらがな1文字の正規表現の用途には使えない。
スクリプト(Scripts、用字)
UAX #24: Unicode Script PropertyScript.txt
perlunicode - Perl における Unicode サポート - perldoc.jp (Scripts)
Scripts.txtの中では、Hiraganaは以下の範囲である。
(※Unicodeスカラー値(の範囲) ; スクリプト名 # 一般カテゴリー名 ([文字数]) Unicode文字名(の範囲) // 実際の字(本文書で追加))
3041..3096 ; Hiragana # Lo [86] HIRAGANA LETTER SMALL A..HIRAGANA LETTER SMALL KE // [ぁ-ゖ]結合用/独立の濁点半濁点は除かれている。
309D..309E ; Hiragana # Lm [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK // [ゝゞ]
309F ; Hiragana # Lo HIRAGANA DIGRAPH YORI // [ゟ]
1B001 ; Hiragana # Lo HIRAGANA LETTER ARCHAIC YE // ヤ行エ段の文字
1F200 ; Hiragana # So SQUARE HIRAGANA HOKA // ほかの組み文字
# Total code points: 91
U+1B001はUnicode 6.0.0で追加されたヤ行エ段の「江」由来の「え」である。
Unicode Character 'HIRAGANA LETTER ARCHAIC YE' (U+1B001)
この字については以下のWebに詳しい。
二つの「え」の話
U+1F200は「ほか」の組み文字である。
Unicode Character 'SQUARE HIRAGANA HOKA' (U+1F200)
Perlで、U+hhhhというUnicodeスカラー値をもつUnicodeは\N{U+hhhh}で書ける。
ということで、Scripts.txtに従えば、[ぁ-ゖゝゞゟ\N{U+1B001}\N{U+1F200}]の91文字がひらがなということになりそうだ。
プログラムはASCII範囲で書くことを考えれば、全部Unicodeスカラー値を使って[\N{U+3041}-\N{U+3096}\N{U+309D}-\N{U+309F}\N{U+1B001}\N{U+1F200}]と書けばいいかもしれない。
いや、そんなこと普通は書いてられないと思う。
Unicodeスクリプト名は、Perlの正規表現では\p{スクリプト名}を使って書ける。
だから、\p{Hiragana}と書けばこの91文字にマッチする。
ひらがな1文字だから\p{Hiragana}。
ハンディだ。
ブロック
Unicodeの分け方としては、スクリプトの他にブロックもある。UAX #44: Unicode Character Database (Block)
Blocks.txt
ブロックとスクリプトは範囲が違う。Blocks.txtの中でひらがなはこのように書かれている。
3040..309F; HiraganaHiraganaブロックに入っていて、Hiraganaスクリプトに入っていないのは以下の3コードポイントだ。
U+3040、U+3097、U+3098
ただしこれらの文字は存在しない。
逆にスクリプトに入っていて、ブロックに入っていないのは以下の2文字だ。
U+1B001(ヤ行のエ)、U+1F200(「ほか」の合略文字)
これは、以下のブロックに入っている。
1B000..1B0FF; Kana Supplementこうしてみると、Unicodeブロックは入っている字を字種別に区切ったもので、Unicodeスクリプトは字を文化的に再構成したものだということが分かる。
1F200..1F2FF; Enclosed Ideographic Supplement
さて、Perl正規表現でブロックを使うときは、\p{Inブロック名}のように書く。
Hiraganaブロック([\N{U+3040}-\N{U+3090}])は\p{InHiragana}と書く。
Kana Supplement1文字は\p{InKanaSup}と書く。
Enclosed Ideographic Supplementは、\p{InEnclosedIdeographicSup}と書く。
このブロックの略記法は、以下の文書に乗っている。
perluniprops - perldoc.perl.org
スクリプトは\p{Hiragana}。ブロックは\p{InHiragana}。
結果的に
ということで、Perlでひらがな1文字を表す正規表現はスクリプトを使って\p{Hiragana}のような気がする。もっとも、[ぁ-ゖ]でも十分なような気がする。
短くて、\p[Hiragana]よりも打ち込む手間がかからないし、視認性もバツグンである。
もっと言うと、昔ながらのJIS X 0208の範囲の[ぁ-ん]でも普通は十分な気がする。
「ゕ」とか「ゖ」みたいな、入力が面倒で、使い道もよく分からないひらがなは省いていいのではないだろうか。
「ゔ」は、最近カタカナのウ点(ヴァイオリン、ライヴなど)が復活してきていて、そのふりがなを振る必要があるのであったほうがいい気もするが、JIS X 0208の範囲に「ゔ」は入っていない。
問題は長音記号「ー」(U+30FC)である。
JIS X 0208では、ひらがな(4区)でも、カタカナ(5区)でもなく、特殊文字に入っている。
カタカナのヘとひらがなのへ、カタカナのリとひらがなのりは別の字として区別しているのだが、「ー」は形が1つしかない。
なんでだろー。
Unicodeでも、カタカナのスクリプトKatakanaには入っていない。
Script.txtによると、
30A1..30FA ; Katakana # Lo [90] KATAKANA LETTER SMALL A..KATAKANA LETTER VO // [ア-ヴ]Scripts.txt
30FD..30FE ; Katakana # Lm [2] KATAKANA ITERATION MARK..KATAKANA VOICED ITERATION MARK // [ヽヾ]
30FF ; Katakana # Lo KATAKANA DIGRAPH KOTO // [ヿ](コトの合字)
31F0..31FF ; Katakana # Lo [16] KATAKANA LETTER SMALL KU..KATAKANA LETTER SMALL RO // [ㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ](アイヌ語の発音を移すのに使う小書きカタカナ)
32D0..32FE ; Katakana # So [47] CIRCLED KATAKANA A..CIRCLED KATAKANA WO //(丸で囲まれたカタカナ
3300..3357 ; Katakana # So [88] SQUARE APAATO..SQUARE WATTO // ㌀(アパート)から㍗(ワット)までの組文字
FF66..FF6F ; Katakana # Lo [10] HALFWIDTH KATAKANA LETTER WO..HALFWIDTH KATAKANA LETTER SMALL TU // [ヲ..ッ](半角カナ)
FF71..FF9D ; Katakana # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAKANA LETTER N // [ア..ン](半角カナ)
1B000 ; Katakana # Lo KATAKANA LETTER ARCHAIC E //(「衣」由来の昔のア行エ、http://www.akenotsuki.com/eyeben参照)
# Total code points: 300
ということで、Katakanaスクリプトには、長音記号U+30FC(ー。KATAKANA-HIRAGANA PROLONGED SOUND MARK)は、絶妙に入っていない。
もう1個絶妙に入っていないU+30FBは中黒(・。KATAKANA MIDDLE DOT)である。
どっちも文字名に「KATAKANA」と入っているのに、Katakanaスクリプトに入っていないのである。
なんでだろうね。
だから\p{Katakana}と書くと、「ー」にマッチしないのである。
どうしても使うなら、「・」と「ー」は入ったほうがいいので[\p{Katakana}・ー]と書くのだろうか。
でも、上のScripts.txtにあるように半角カナとか丸で囲んだカタカナなどにもマッチしてしまうので、使わないほうがいいと思う。
ブロックはどうだろうか。
Blocks.txtによると
30A0..30FF; Katakanaということで、常識的なカタカナが全部入る。
(常識的なカタカナって何?>自分)
だから、カタカナはブロックを使って\p{InKatakana}がいいような気がする。
でも、ひらがなはスクリプトを使って\p{Hiragana}で、カタカナはブロックを使って\p{InKatakana}とかいちいち覚えているのは面倒だ。
[ァ-ヴ・ー]で十分用が足りる気もする。
っていうかいつの間にか話がカタカナに流れたが、ひらがなも「・」と「ー」が入った方がいいと思うのなら、こっちはUnicodeスクリプトHiraganaを使う場合は[\p{Hiragana}・ー]と書く。
でも見づらいから、やっぱり[ぁ-ん・ー]でいいかもしれない。
今日の結論。
ひらがな1字の正規表現は[ぁ-ん・ー]、カタカナ1字の正規表現は[ァ-ヴ・ー]がなんだかんだ言ってカンタンで実用的な気がする。
例によって無計画に書いてたらいい長さになってしまった。
以下次週!