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…)を使用してください。