複数のプログラミング言語で正規表現を使いまわそうとしたら \p{...}
(Unicodeプロパティエスケープ)の互換性がよくわからなかったのでメモ。
概要
下表のように、ECMAScript, .NET (C#), Javaでは \p{カテゴリ名}
形式のGeneral Cateogry指定以外の記法は三者に互換性がない。
Unicodeプロパティ | ECMAScript | .NET | Java |
---|---|---|---|
General_Category | \p{Lu} \p{General_Category=Lu} \p{gc=Lu} |
\p{Lu} | \p{Lu} \p{IsLu} \p{General_Category=Lu} \p{gc=Lu} |
Block | - | \p{IsMongolian} | \p{InMongolian} \p{Block=Mongolian} \p{blk=Mongolian} |
Script | \p{Script=Common} \p{sc=Common} |
- | \p{IsCommon} \p{Script=Common} \p{sc=Common} |
Script_Extensions | \p{Script_Extensions=Adlam} \p{scx=Adlam} |
- | - |
Binary Property | \p{Uppercase} | - | \p{IsUppercase} |
以下に、General_Category, Block, Script, Script_Extensionsの取る値を、ひらがなやカタカナを例に説明する。
文字 | コードポイント | 名前 | General_Category | Block | Script | Script_ Extensions |
---|---|---|---|---|---|---|
え | U+3048 | HIRAGANA LETTER E | Lo | Hiragana | Hiragana | {Hiragana} |
エ | U+30A8 | KATAKANA LETTER E | Lo | Katakana | Katakana | {Katakana} |
ー | U+30FC | KATAKANA-HIRAGANA PROLONGED SOUND MARK | Lm | Katakana | Common | {Hiragana, Kanakana} |
𛀁 | U+1B001 | HIRAGANA LETTER ARCHAIC YE | Lo | Kana Supplement | Hiragana | {Hiragana} |
General_Categoryはコードポイントの最も一般的な分類を表す。ひらがなやカタカナは、大文字小文字といった区別のない文字なのでLo(Letter Other)カテゴリに属し、音引きは他の文字のあとについて長音を表す文字なのでLm(Letter Modifier)カテゴリに属す。
Blockは連続する符号位置の範囲に名前をつけたものである。や行え(HIRAGANA LETTER ARCHAIC YE)は文字の種別としてはひらがなであるが、ブロックとしては仮名補助(Kana Supplement。U+1B000..U+1B0FF)に属す。
Scriptは、その文字がどの書記体系(用字、スクリプト)で用いられるかを表す。ここでは、や行えはHiragana扱いになり、音引きはひらがなとカタカナ両方で使われるためCommonになる。
Script_Extensionsは、複数の値を取れるようScriptを拡張したものである。音引きはここではHiragana, Katakana両方に属する扱いになる。
言語比較
ECMAScript
ECMAScript 2019時点の状況について述べる。
ECMAScript 2018以降の、Unicodeフラグ付きの正規表現で使用できる。
\p{プロパティ名=プロパティ値}
の形で指定する。
プロパティ名が General_Category
の場合は省略して \p{プロパティ値}
と書ける(例: \p{Lu}
)。
Yes/No の二値を取るプロパティ(バイナリプロパティ)は \p{プロパティ名}
と書く(例: \p{Uppercase}
。\p{Uppercase=Yes}
のようには書けない)。
非バイナリプロパティとしては ECMAScript® 2019 Language Specification #Table 54: Non-binary Unicode property aliases and their canonical property names に列挙されているGeneral_Category
, Script
, Script_Extensions
と、その別名であるgc
, sc
, scx
が使用できる(Block
は含まれないため、ブロック指定はできない。Block
はnot usefulということでproposal段階で除外された —— Which properties should we include in Unicode escapes? · Issue #18 · tc39/proposal-regexp-unicode-property-escapes)。
バイナリプロパティとしては ECMAScript® 2019 Language Specification #Table 55: Binary Unicode property aliases and their canonical property names に列挙されているプロパティが使用できる。
.NET
General CategoryとBlock指定のみ使用できる。
General Categoryは \p{カテゴリ名}
と記述する。カテゴリ名には .NET 正規表現での文字クラス | Microsoft Docs #サポートされている Unicode 一般カテゴリに列挙されている名前が使用できる。 .NET FrameworkのバージョンとUnicode標準のバージョンの対応関係は CharUnicodeInfo クラス (System.Globalization) | Microsoft Docs を参照。
Blockは \p{Isブロック名}
と記述する。ブロック名には .NET 正規表現での文字クラス | Microsoft Docs #サポートされている名前付きブロックに列挙されている名前が使用できる。ここで指定できる名前はUnicode 4.0 および Perl 5.6に基づいている。
Java
Java 11時点の状況について述べる。
General Category, Block, Script, バイナリプロパティ指定が使用できる。
General Categoryは \p{カテゴリ名}
, \p{Isカテゴリ名}
, \p{General_Category=カテゴリ名}
と記述する。指定できるカテゴリ名の集合は Characterクラスで指定されたUnicodeバージョンで定義されているカテゴリ名の集合に等しい。
Blockは \p{Inブロック名}
, \p{Block=ブロック名}
と記述する。指定可能なブロック名は Character.UnicodeBlock#forName(String) の受け付ける名前とされている。UnicodeバージョンはCharacterクラスの指定に準じる。
Scriptは \p{Isスクリプト名}
, \p{Script=スクリプト名}
と記述する。指定可能なスクリプト名は Character.UnicodeScript#forName(String) の受け付ける名前とされている。UnicodeバージョンはCharacterクラスの指定に準じる。
バイナリプロパティは \p{Isプロパティ名}
と記述する。指定可能なバイナリプロパティは Patternクラスのドキュメントに列挙されている。
参考: 鬼雲(Ruby)
鬼雲(Ruby)で使用可能なUnicodeプロパティは https://github.com/k-takata/Onigmo/blob/master/doc/UnicodeProps.txt に列挙されている。
ブロック名は In_ブロック名
の形式、 Ageは Age=バージョン
の形式、それ以外は プロパティ値
の形式になっているようだ。
参考: PCRE
PCREの \p
で利用可能なプロパティは pcre2pattern(3) で説明されている。
\p{プロパティ値}
の形式で、 General Categoryの値、Scriptの値、 Any
と、PCRE拡張として Xan
, Xps
, Xsp
, Xwd
が指定できる。
UTS #18: Unicode Regular Expressions
UTS #18: Unicode Regular Expressions ver. 19 §1.2 Properties では、正規表現でUnicodeプロパティに対応する際のガイドラインを示している。
構文は以下の通りで、ECMAScriptの \p
のスーパーセットになっている。Javaもブロックの \p{Inブロック名}
以外はこの形式だ。
ITEM := POSITIVE_SPEC | NEGATIVE_SPEC
POSITIVE_SPEC := ("\p{" PROP_SPEC "}") | ("[:" PROP_SPEC ":]")
NEGATIVE_SPEC := ("\P{" PROP_SPEC "}") | ("[:^" PROP_SPEC ":]")
PROP_SPEC := <binary_unicode_property>
PROP_SPEC := <unicode_property> (":" | "=" | "≠" | "!=" ) VALUE
PROP_SPEC := <script_or_category_property_value> ("|" <script_or_category_property_value>)*
PROP_VALUE := <unicode_property_value> ("|" <unicode_property_value>)*
\p
, \P
以外にPOSIX文字集合形式の [:spec:]
, [:^spec:]
が書けたり、 =
の別名として :
があったり、 =
の代わりに ≠
や !=
と書くことで否定が表現できる。また、バイナリプロパティやGeneral Category以外にもScriptプロパティ値も \p{スクリプトプロパティ値}
で書けることになっている。
ECMAScriptでは、同一機能の別表記を取り入れるのは実装を複雑にするだけであること、実用上はScriptよりScript_Extensionsの方が有用なため後者を推奨するといった立場からこれらの機能は取り入れなかったようだ。
ECMAScriptはUAX44-LM3のマッチング規則(シンボル値に関して (1) 大文字小文字を区別しない、 (2) -
, _
, 空白は無視する、 (3) 先頭の is
は無視する)も採用していない。