JavaScriptは文字列にUnicodeエンコーディングを使用します。ほとんどの文字は2バイトでエンコードされますが、最大65536文字まで表現できます。
この範囲は、すべての可能な文字をエンコードするには十分ではありません。そのため、一部のまれな文字は4バイトでエンコードされます。たとえば、𝒳
(数学のX)や😄
(笑顔)、一部の象形文字などです。
いくつかの文字のUnicode値を以下に示します
文字 | Unicode | Unicodeでのバイト数 |
---|---|---|
a | 0x0061 |
2 |
≈ | 0x2248 |
2 |
𝒳 | 0x1d4b3 |
4 |
𝒴 | 0x1d4b4 |
4 |
😄 | 0x1f604 |
4 |
そのため、a
や≈
のような文字は2バイトを占めますが、𝒳
、𝒴
、😄
のコードはより長く、4バイトです。
ずっと昔、JavaScript言語が作成されたとき、Unicodeエンコーディングはよりシンプルでした。4バイト文字はありませんでした。そのため、一部の言語機能はそれらを正しく処理しません。
たとえば、length
はここに2文字あると考えています
alert('😄'.length); // 2
alert('𝒳'.length); // 2
…しかし、実際には1文字だけですよね?問題は、length
が4バイトを2つの2バイト文字として扱うことです。これは正しくありません。なぜなら、それらは一緒に考慮する必要があるからです(いわゆる「サロゲートペア」。文字列の記事で読むことができます)。
デフォルトでは、正規表現も4バイトの「長い文字」を2バイトのペアとして扱います。そして、文字列の場合と同様に、奇妙な結果につながる可能性があります。これは、集合と範囲[...]の記事で後ほど説明します。
文字列とは異なり、正規表現には、このような問題を修正するフラグu
があります。このフラグを使用すると、正規表現は4バイト文字を正しく処理します。また、Unicodeプロパティ検索が利用可能になります。次に説明します。
Unicodeプロパティ \p{…}
Unicodeのすべての文字には、多くのプロパティがあります。それらは、文字が属する「カテゴリ」を記述し、それに関するその他の情報を含んでいます。
たとえば、文字にLetter
プロパティがある場合、その文字は(任意の言語の)アルファベットに属することを意味します。また、Number
プロパティは、それが数字であることを意味します。アラビア語または中国語などです。
\p{…}
と記述されたプロパティを持つ文字を検索できます。\p{…}
を使用するには、正規表現にフラグu
が必要です。
たとえば、\p{Letter}
は任意の言語の文字を表します。L
はLetter
のエイリアスであるため、\p{L}
も使用できます。ほとんどすべてのプロパティに短いエイリアスがあります。
以下の例では、英語、グルジア語、韓国語の3種類の文字が見つかります。
let str = "A ბ ㄱ";
alert( str.match(/\p{L}/gu) ); // A,ბ,ㄱ
alert( str.match(/\p{L}/g) ); // null (no matches, \p doesn't work without the flag "u")
主な文字カテゴリとそのサブカテゴリを以下に示します
- 文字
L
- 小文字
Ll
- 修飾子
Lm
- タイトルケース
Lt
- 大文字
Lu
- その他
Lo
- 小文字
- 数字
N
- 10進数字
Nd
- 文字数字
Nl
- その他
No
- 10進数字
- 句読点
P
- コネクタ
Pc
- ダッシュ
Pd
- 開始引用符
Pi
- 終了引用符
Pf
- 開き
Ps
- 閉じ
Pe
- その他
Po
- コネクタ
- マーク
M
(アクセントなど)- スペース結合
Mc
- 囲み
Me
- 非スペース
Mn
- スペース結合
- 記号
S
- 通貨
Sc
- 修飾子
Sk
- 数学
Sm
- その他
So
- 通貨
- 区切り文字
Z
- 行
Zl
- 段落
Zp
- スペース
Zs
- 行
- その他
C
- 制御
Cc
- フォーマット
Cf
- 未割り当て
Cn
- 私用
Co
- サロゲート
Cs
- 制御
そのため、たとえば小文字の文字が必要な場合は\p{Ll}
、句読点の場合は\p{P}
などと書くことができます。
他にも次のような派生カテゴリがあります。
Alphabetic
(Alpha
) には、文字L
と文字数字Nl
(例:Ⅻ - ローマ数字12の文字) とその他の記号Other_Alphabetic
(OAlpha
) が含まれます。Hex_Digit
には、16進数字が含まれます:0-9
、a-f
。- …など。
Unicodeは多くの異なるプロパティをサポートしており、それらの完全なリストには多くのスペースが必要になるため、ここに参考文献を示します
- 文字ごとのすべてのプロパティを一覧表示:https://unicode.org/cldr/utility/character.jsp。
- プロパティごとのすべての文字を一覧表示:https://unicode.org/cldr/utility/list-unicodeset.jsp。
- プロパティの短いエイリアス:https://www.unicode.org/Public/UCD/latest/ucd/PropertyValueAliases.txt。
- すべてのプロパティを含むテキスト形式のUnicode文字の完全なベースは次のとおりです:https://www.unicode.org/Public/UCD/latest/ucd/。
例:16進数
たとえば、xFF
のように記述された16進数を検索してみましょう。ここで、F
は16進数字(0…9またはA…F)です。
16進数字は\p{Hex_Digit}
と表すことができます
let regexp = /x\p{Hex_Digit}\p{Hex_Digit}/u;
alert("number: xAF".match(regexp)); // xAF
例:漢字
漢字を探してみましょう。
Script
(書記体系)というUnicodeプロパティがあり、値はCyrillic
、Greek
、Arabic
、Han
(中国語)などです。完全なリストはこちら。
特定の書記体系の文字を検索するには、Script=<value>
を使用する必要があります。たとえば、キリル文字の場合は\p{sc=Cyrillic}
、漢字の場合は\p{sc=Han}
などです。
let regexp = /\p{sc=Han}/gu; // returns Chinese hieroglyphs
let str = `Hello Привет 你好 123_456`;
alert( str.match(regexp) ); // 你,好
例:通貨
$
、€
、¥
などの通貨を表す文字には、Unicodeプロパティ\p{Currency_Symbol}
(短いエイリアス:\p{Sc}
)があります。
これを使用して、「通貨、その後に数字」の形式で価格を検索してみましょう
let regexp = /\p{Sc}\d/gu;
let str = `Prices: $2, €1, ¥9`;
alert( str.match(regexp) ); // $2,€1,¥9
後で、量指定子 +, *, ? and {n}の記事で、多くの数字を含む数字を検索する方法を説明します。
まとめ
フラグu
は、正規表現でのUnicodeのサポートを有効にします。
これは2つのことを意味します
- 4バイトの文字は、2つの2バイト文字ではなく、単一の文字として正しく処理されます。
- Unicodeプロパティは検索で使用できます:
\p{…}
。
Unicodeプロパティを使用すると、特定の言語の単語、特殊文字(引用符、通貨)などを検索できます。
コメント
<code>
タグを使用し、複数行の場合は<pre>
タグで囲み、10行を超える場合はサンドボックス(plnkr、jsbin、codepen…)を使用してください。