GitBookjs-primer文字列とUnicode「文字列」の章で紹介したように、JavaScriptは文字コードとしてUnicodeを採用し、エンコード方式としてUTF-16を採用しています。このUTF-16を採用しているのは、あくまでJavaScriptの内部で文字列を扱う際の文字コード(内部コード)です。そのため、コードを書いたファイル自体の文字コード(外部コード)は、UTF-8のようにUTF-16以外の文字コードであっても問題ありません。「文字列」の章では、これらの文字コードは意識していなかったように、内部的にどのような文字コードで扱っているかは意識せずに文字列処理ができます。JavaScriptのStringオブジェクトにはこの文字コード(Unicode)に特化したAPIもあります。絵文字を含む特定の文字を扱う際や「文字数」を数えるという場合には、内部コードであるUTF-16を意識しないといけない場面があります。この章では、文字列におけるUnicodeを意識しないといけない場面について見ていきます。Unicode自体もECMAScriptと同じように歴史がある仕様であり、Unicodeのすべてを紹介するには膨大な文字列が必要になります。そのため、この章はJavaScriptにおけるUnicodeとUTF-16に話を限定しています。Unicodeの歴史を含めた文字コード自体について詳しく知りたい方は「プログラマのための文字コード技術入門」や「文字コード「超」研究」等を参照してください。PointUnicodeはすべての文字(制御文字などの画面に表示されない文字も含む)に対してIDを定義する目的で策定されている仕様です。Point(符号位置)と呼びます。2015で追加されています。Pointを相互変換できます。Pointの値を返します。Pointに対応する文字を返します。Pointを書くこともできます。Pointの16進数の値}のようにエスケープシーケンスとして記述できます。Pointの16進数の値が必要となります。Number#toStringメソッドの引数に基数となる16を渡すことで、16進数の文字列を取得できます。Unit(符号単位)です(詳細は「文字列」の章を参照)。Unit(符号単位)は結果として同じ値となります。Unitとして表示しています。Pointの配列にしています。それぞれの関数の実装はまだ理解しなくても問題ありません。Unitが同じ値になっていることがわかります。Unitが異なる値となる場合があります。Pointを見比べてみます。Unitが異なる値となることがわかります。Unitの要素数が5つになっています。Unitで🍎に対応しています。Unitの個数である5つとなっています。Unitで表現するのがUTF-16というエンコード方式です。16bit(2バイト)で表現できる範囲は、65536種類(2の16乗)です。Unitを1対1の関係で表すことができません。Point)を表現します。この仕組みをサロゲートペアと呼びます。Point)を表現します。UTF-16では、次の範囲をサロゲートペアに利用する領域としています。Point)として扱います。Unitで表現しています。Unitのエスケープシーケンス(\uXXXX)を2つ並べることで𩸽という文字を表現できます。Pointで𩸽という文字を表現できることもわかります。Unitに変換された値で保持されることは変わりません。"𩸽"先ほどの例で登場した🍎(リンゴの絵文字)もサロゲートペアで表現される文字です。Pointを表現します。Unitごとに作用します。Unitごととなります。そのため、サロゲートペアで表現している文字列では、上位サロゲート(0番目)と下位サロゲート(1番目)へのインデックスアクセスになります。Unitごとに扱う文字列処理は複雑になります。Unitの要素数を数えるため、"🍎".lengthの結果は2となります。Pointごとに処理することを考える必要があります。Pointに対応したメソッドなどを利用する必要があります。Pointごとに扱うメソッドや構文が追加されています。Pointごとに扱います。Pointを扱う処理と具体的な使い方を見ていきます。正規表現の.とUnicodeES2015では、正規表現にu(Unicode)フラグが追加されました。Pointが順番に並んだものとして扱います。具体的にuフラグの有無による.(改行文字以外のどの1文字にもマッチする特殊文字)の動作の違いを見ていきます。/(.)のひらき/というパターンで.にマッチする部分を取り出すことを例に見ていきます。uフラグをつけていない正規表現とString#matchメソッドでマッチした範囲を取り出してみます。キャプチャされた文字列]です(詳細は「文字列」の章を参照)。実際にマッチした結果を見てみると、.は𩸽の下位サロゲートである\ude3dにマッチしていることがわかります(\ude3dは単独では表示できないため、文字化けのように表示されます)。Unitが順番に並んだものとして扱っています。このような意図しない結果を避けるには、正規表現にuフラグをつけます。Pointごとに扱います。Point)にマッチします。"𩸽"基本的には正規表現にuフラグをつけて問題となるケースは少ないはずです。サロゲートペアの片方だけにマッチしたい正規表現を書くケースはまれであるためです。Unitの個数を表すプロパティです。そのためサロゲートペアを含む文字列では、lengthの結果が見た目より大きな値となる場合があります。Pointの個数を数えるメソッドは用意されていません。Pointごとに区切った配列へ変換して、配列の長さを数えるのが簡潔です。Array.fromメソッド[ES2015]は、引数にiterableなオブジェクトを受け取り、それを元にした新しい配列を返します。iterableオブジェクトとはSymbol.iteratorという特別な名前のメソッドを実装したオブジェクトの総称で、for...of文などで反復処理が可能なオブジェクトです(詳細は「ループと反復処理のfor...of文」を参照)。Point)ごと区切った配列へと変換できます。Pointごとに処理を行います。Pointの数を数えた場合でも、直感的な結果にならない場合もあります。Pointには制御文字などの視覚的に見えないものも定義されているためです。そのため、文字として数えたくないものは無視するなど、視覚的な文字列の長さを数えるにはさらなる工夫が必要になります。残念ながら、ビルトインメソッドにはこれらを簡単に扱う方法は用意されていません。Pointで区切った文字の配列へと変換できます。Pointごとに反復処理ができます。次のコードでは、文字列中に登場する🍎の個数を数えています。Pointごとの配列にし、配列をcodePointでフィルターした結果できた配列の要素数を返します。Pointごとに扱えます。これは、for...of文が対象をIteratorとして列挙するためです。先ほどのコードと同じcountOfCodePoints関数をfor...ofを使って実装してみます。2終わりにこの章では、文字列とUnicodeの関係について簡潔に紹介しました。Unicodeにはこの章で紹介しきれなかった表現もあります。JavaScriptにはUnicodeをキレイに扱うAPIが用意されているとは言い切れない部分もあります。Pointを意識しなくても柔軟で強力な文字列処理ができます。Pointを意識したプログラミングが必要となるケースも増えています。UnicodeはECMAScriptとは独立した仕様であるため、文字列を扱う悩みはプログラミング言語を問わずに出てくる共通の課題です。JavaはJavaScriptと同じくUTF-16をエンコード方式として採用しているため、類似する問題が見られます。そのため、JavaScriptで文字列処理の問題にぶつかった際には、他の言語ではどうしているかを調べることも重要です。