yutaponのブログ

javascript界隈の興味あるネタを備忘録的に残しておく場所

ES2018で入ったUnicode property escapes in regular expressionsを調べてみた

はじめに

ES2018で正規表現まわりの機能にいくつかの便利な表現が入った。

例えばこんな感じ。
いずれもChrome*1 のコンソールで入力して試すことができる。

// `ひらがな` のみの文字列ならtrue
/^\p{sc=Hiragana}+$/u.test('あいうえお') // true

// `カタカナ` のみの文字列ならtrue
/^\p{sc=Katakana}+$/u.test('アイウエオ㍑㍍') // true

// `漢字` のみの文字列ならtrue
/^\p{sc=Han}+$/u.test('𠮷野家') // true

// `漢字` 以外が含まれているのでfalse
/^\p{sc=Han}+$/u.test('㍻㍼') // false

// `漢字っぽい文字` のみの文字列ならtrue
/^\p{scx=Han}+$/u.test('平成昭和㍻㍼') // true

使い方

unicode property escapes を使うには RegExp オブジェクト生成時に u フラグを渡す必要がある。

次に \p{sc=Hiragana}+ のように \p から始めると ひらがな にマッチし、 \P{sc=Hiragana}+ のように \P から始めると ひらがな以外 にマッチする。

書式について

// positive match
\p{UnicodePropertyName=UnicodePropertyValue}

// negative match
\P{UnicodePropertyName=UnicodePropertyValue}

という書式で指定する。

では UnicodePropertyNameUnicodePropertyValue に指定できるものは何か調べてみた。

UnicodePropertyName

UnicodePropertyName に指定できるものは以下の通り。

  • General_Category (gc)
  • Script (sc)
  • Script_Extensions (scx)
  • プラスして、Binary Unicode property (後述) というのを指定できる

General_Category

General_Category は特定の言語(英語、日本語、フランス語など)に依存しない、全般的な文字が属するカテゴリーが定義されている。

以下は General_Category が取りうる値の一例。

  • Letter (L)
    • aAあア亜 など文章に使うような文字は true になる*2
    • *-2[.㍑㍼\\ など数値や記号のような文字は false になる
  • Number (N)
    • 1234① などの数字としての意味を持つ文字は true になる
      • ²³¹¼½¾𝟏𝟐𝟑𝟜𝟝𝟞𝟩𝟪𝟫𝟬𝟭𝟮𝟯𝟺𝟻𝟼㉛ⅠⅡⅢⅣⅤⅪⅫⅬⅭⅮⅯⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿ
      • これらも true になるので、思ったより多くの文字が該当する
    • '一壱aI=あ' などの数字として使えない文字は false になる
  • Symbol (S)
    • ⒜🄐☟☡☤㏪😀 などの記号としての意味を持つ文字が true になる

また General_Category は書式でいうところの UnicodePropertyName を省略して書くことができる。

たとえば以下のコードはすべて同じ結果になる。

// 通常のフォーマットに則るとこう書く
/^\p{General_Category=Letter}+$/u.test('abcABCあいうサシスハンカク') // true

// `General_Category` は `gc` と省略できる
/^\p{gc=Letter}+$/u.test('abcABCあいうサシスハンカク') // true

// `General_Category` はプロパティ名自体省略できる
/^\p{Letter}+$/u.test('abcABCあいうサシスハンカク') // true

General_Category にどんな Value を指定できるかについてはこちら。

https://tc39.github.io/proposal-regexp-unicode-property-escapes/#sec-runtime-semantics-unicodematchpropertyvalue-p-v

Script, Script_Extensions

General_Category はどんな言語においても共通するような値が定義されていたのに対して、Script というのは言語(英語、日本語、フランス語など)特有の文字が定義されている。

日本語に関して言えば Hiragana (Hira) , Katakana (Kana) , Han などが使いやすそうである。

// `ひらがな` のみの文字列で構成されているか
/^\p{sc=Hiragana}+$/u.test('あいうえお') // true

// `カタカナ` のみの文字列で構成されているか
/^\p{sc=Katakana}+$/u.test('アイウエオ㍑㍍') // true

// `漢字` のみの文字列で構成されているか
^\p{sc=Han}+$/u.test('𠮷野家') // true

Script_Extensions とはある Script に属する文字を、別な Script でも使えるように拡張したものである。

簡単な例を挙げると、

// 1.
/^\p{sc=Hira}+$/u.test('るびー') // false 

// 2.
/^\p{scx=Hira}+$/u.test('るびー') // true
  1. (伸ばし棒)が Script=Hiragana に属さないため false になる
  2. (伸ばし棒)が Script_Extensions=Hiragana,Katakana に属しているため true になる

Script_Extensions (Unicode)についてとても分かりやすく解説されている記事があったので、詳しくはこちらを参照してほしい。

JavaScriptのUnicode Property Escapesについての補説

Binary Unicode property

Binary Unicode property とはある Unicode の文字に付随している YES / NO で設定される属性のことである。

binary という意味の通りプロパティの値は YES or NO になる。
UnicodePropertyValue を省略して書くので、書式はこのようになる。

// positive match
\p{BinaryUnicodePropertyName}

// negative match
\P{BinaryUnicodePropertyName}

こんな感じで指定できる。

// ASCII 文字のみで構成されているか
/^\p{ASCII}+$/u.test('abcde*10') // true

// 絵文字が含まれているか
/\p{Emoji}+/u.test('robot 🤖!') // true

// 大文字のみで構成されているか
/^\p{Uppercase}+$/u.test('AAAA') // true

// 空白が含まれているか
/\p{space}+/u.test(' ') // true

指定できるPropertyの一覧はこちら。

https://tc39.github.io/proposal-regexp-unicode-property-escapes/#table-binary-unicode-properties

※ Unicode 側で binary property が設定されていても、JS 側で参照できる(実装されている)とは限らないので、利用するときは上記の一覧を一度見ておいたほうがいい。

調べ方

UnicodePropertyValue に属する文字一覧を調べる

こちらから調べることができる。

http://unicode.org/cldr/utility/properties.jsp

例えば Script=Hiragana に属する文字一覧を見たい場合は、上記リンクより General > Catalog > Script の SHOW VALUES のリンクを開く。

次に Hiragana で検索するか、General > Catalog > Script にある Hiragana (Hira) のリンクを開く。

これで Script=Hiragana に属する文字の一覧が見れる。
(: ひらがなの小文字の などがあって発見がある。)

ある文字に指定されている属性を調べる

こちらから調べることができる。

Unicode Utilities: Character Properties

たとえば (伸ばし棒) を検索すると、

  • Unicode上の名前は KATAKANA-HIRAGANA PROLONGED SOUND MARK という
  • Unicode v1.1 で追加された
  • Script=Common に属する
  • 様々な binary property が設定されている

などがわかる。

おわりに

ES2018 では正規表現まわりの機能が強化され、JS でも正規表現で UnicodePropertyName を使えるようになった*3
これによって読みにくくなりがちであった正規表現が読みやすくなるかもしれない。

今回この機能を調べるにあたり Unicode についても理解が深まった。
特に絵文字まわりが難しかったのでまたの機会にまとめてみようと思う。

参考にした記事

*1:Chrome v64から実装された

*2:とても意訳している

*3:Golang, Java, Ruby, etc.. など別な言語では既にサポートしていた