高度な知識
このセクションでは、文字列の内部について詳しく説明します。この知識は、絵文字、珍しい数学文字、象形文字、またはその他の珍しい記号を扱う予定がある場合に役立ちます。
すでにご存知のとおり、JavaScript 文字列は Unicode に基づいており、各文字は 1 ~ 4 バイトのバイト シーケンスで表されます。
JavaScript では、次の 3 つの表記法のいずれかを使用して 16 進 Unicode コードを指定することで、文字列に文字を挿入できます。
xXX
XX
00
からFF
までの値を持つ 2 桁の 16 進数でなければなりません。その場合、 xXX
は Unicode コードがXX
である文字です。
xXX
表記は 2 桁の 16 進数のみをサポートするため、最初の 256 個の Unicode 文字にのみ使用できます。
これらの最初の 256 文字には、ラテン文字、最も基本的な構文文字、およびその他の文字が含まれます。たとえば、 "x7A"
"z"
(Unicode U+007A
)と同じです。
アラート( "x7A" ); //z アラート( "xA9" ); // ©、著作権記号
uXXXX
XXXX
0000
からFFFF
までの値を持つ 4 桁の 16 進数でなければなりません。その場合、 uXXXX
は Unicode コードがXXXX
である文字になります。
U+FFFF
より大きい Unicode 値を持つ文字もこの表記法で表すことができますが、この場合、いわゆるサロゲート ペアを使用する必要があります (サロゲート ペアについてはこの章で後ほど説明します)。
アラート( "u00A9" ); // ©、xA9 と同じ、4 桁の 16 進表記を使用 アラート( "u044F" ); // я、キリル文字 アラート( "u2191" ); // ↑、上矢印記号
u{X…XXXXXX}
X…XXXXXX
0
~ 10FFFF
(Unicode で定義されている最高のコード ポイント) の 1 ~ 6 バイトの 16 進数値である必要があります。この表記法を使用すると、既存のすべての Unicode 文字を簡単に表すことができます。
アラート( "u{20331}" ); // 佫、珍しい漢字 (長い Unicode) アラート( "u{1F60D}" ); // ?、笑顔の記号 (これも長い Unicode)
頻繁に使用されるすべての文字には 2 バイト コード (4 桁の 16 進数) が含まれています。ほとんどのヨーロッパ言語の文字、数字、および基本的な統一 CJK 表意文字セット (CJK – 中国語、日本語、韓国語の表記体系から) は 2 バイト表現です。
当初、JavaScript は 1 文字あたり 2 バイトのみを許可する UTF-16 エンコーディングに基づいていました。ただし、2 バイトでは 65536 個の組み合わせしか許可されず、Unicode のすべての可能な記号には十分ではありません。
そのため、2 バイトを超えるまれな記号は、「サロゲート ペア」と呼ばれる 2 バイト文字のペアでエンコードされます。
副作用として、このようなシンボルの長さは2
なります。
アラート( '?'.length ); // 2、数学スクリプト大文字 X アラート( '?'.length ); // 2、喜びの涙を流す アラート( '?'.length ); // 2、珍しい漢字
これは、JavaScript が作成された時点ではサロゲート ペアが存在しなかったため、言語によって正しく処理されないためです。
実際には、上記の各文字列には 1 つのシンボルがありますが、 length
プロパティの長さは2
を示しています。
ほとんどの言語機能はサロゲート ペアを 2 文字として扱うため、シンボルの取得も難しい場合があります。
たとえば、ここでは出力に 2 つの奇妙な文字が表示されます。
アラート( '?'[0] ); // 奇妙な記号が表示されます... アラート( '?'[1] ); // ...サロゲートペアの部分
サロゲート ペアの各部分は、お互いがなければ意味を持ちません。したがって、上記の例のアラートには実際にはガベージが表示されます。
技術的には、サロゲート ペアはコードによっても検出できます。文字の範囲が0xd800..0xdbff
の場合、それはサロゲート ペアの最初の部分です。次の文字 (2 番目の部分) には、間隔0xdc00..0xdfff
のコードが含まれている必要があります。これらの間隔は、標準によりサロゲート ペア専用に予約されています。
そこで、サロゲート ペアを処理するために、メソッド String.fromCodePoint および str.codePointAt が JavaScript に追加されました。
これらは基本的に String.fromCharCode および str.charCodeAt と同じですが、サロゲート ペアを正しく処理します。
ここで違いがわかります。
// charCodeAt はサロゲート ペアを認識しないため、? の最初の部分のコードが与えられます。 アラート( '?'.charCodeAt(0).toString(16) ); // d835 // codePointAt はサロゲート ペアを認識します アラート( '?'.codePointAt(0).toString(16) ); // 1d4b3、サロゲート ペアの両方の部分を読み取ります
とはいえ、位置 1 から取得すると (これはかなり不正確です)、両方ともペアの 2 番目の部分のみを返します。
アラート( '?'.charCodeAt(1).toString(16) ); // dcb3 アラート( '?'.codePointAt(1).toString(16) ); // dcb3 // ペアの後半は無意味
サロゲート ペアを処理するその他の方法については、「Iterables」の章で後ほど説明します。おそらくそれ用の特別なライブラリもあるでしょうが、ここで提案できるほど有名なものはありません。
要点: 文字列を任意の位置で分割するのは危険です
文字列を任意の位置で単純に分割することはできません。たとえば、 str.slice(0, 4)
を取得し、それが有効な文字列であることを期待します。たとえば、次のようになります。
アラート( 'こんにちは ?'.slice(0, 4) ); // こんにちは [?]
ここでは、出力にガベージ文字 (smile サロゲート ペアの前半) が含まれていることがわかります。
サロゲート ペアを確実に操作したい場合は、この点に注意してください。大きな問題ではないかもしれませんが、少なくとも何が起こるかを理解する必要があります。
多くの言語には、基本文字とその上/下のマークで構成される記号があります。
たとえば、文字a
、 àáâäãåā
文字の基本文字になります。
一般的な「複合」文字のほとんどは、Unicode テーブルに独自のコードを持っています。ただし、考えられる組み合わせが多すぎるため、すべてではありません。
任意の構成をサポートするために、Unicode 標準ではいくつかの Unicode 文字、つまり基本文字の後に、それを「装飾」する 1 つまたは複数の「マーク」文字が続くものを使用することができます。
たとえば、 S
後に特殊な「上のドット」文字 (コードu0307
) が続く場合、それは Ṡ と表示されます。
アラート( 'Su0307' ); //Ṡ
文字の上 (または下) に追加のマークが必要な場合は、必要なマーク文字を追加するだけで問題ありません。
たとえば、「下にドット」という文字を追加すると (コードu0323
)、「上下にドットのある S」: Ṩ
になります。
例えば:
アラート( 'Su0307u0323' ); //Ṩ
これにより、優れた柔軟性が得られますが、興味深い問題もあります。つまり、2 つの文字は視覚的には同じに見えますが、異なる Unicode 構成で表現される可能性があります。
例えば:
s1 = 'Su0307u0323'; // Ṩ, S + 上のドット + 下のドット s2 = 'Su0323u0307'; // Ṩ, S + 下のドット + 上のドット アラート( `s1: ${s1}, s2: ${s2}` ); アラート( s1 == s2 ); // 文字は同じに見えますが (?!)
これを解決するために、各文字列を単一の「標準」形式にする「Unicode 正規化」アルゴリズムが存在します。
これは str.normalize() によって実装されます。
alert( "Su0307u0323".normalize() == "Su0323u0307".normalize() ); // 真実
面白いことに、この状況では、 normalize()
実際に 3 文字のシーケンスを 1 つにまとめます: u1e68
(S と 2 つのドット)。
alert( "Su0307u0323".normalize().length ); // 1 alert( "Su0307u0323".normalize() == "u1e68" ); // 真実
実際には、常にそうとは限りません。その理由は、記号Ṩ
が「十分に一般的」であるため、Unicode 作成者がそれをメイン テーブルに含めてコードを与えたためです。
正規化ルールとそのバリアントについて詳しく知りたい場合は、Unicode 標準の付録「Unicode 正規化形式」で説明されていますが、ほとんどの実用的な目的には、このセクションの情報で十分です。