JavaScriptでは、テキストデータは文字列として格納されます。単一の文字のための個別の型はありません。
文字列の内部形式は常にUTF-16であり、ページエンコーディングには依存しません。
引用符
引用符の種類を思い出してみましょう。
文字列は、シングルクォート、ダブルクォート、またはバッククォートで囲むことができます。
let single = 'single-quoted';
let double = "double-quoted";
let backticks = `backticks`;
シングルクォートとダブルクォートは基本的に同じです。しかし、バッククォートを使用すると、${…}
で囲むことで、任意の式を文字列に埋め込むことができます。
function sum(a, b) {
return a + b;
}
alert(`1 + 2 = ${sum(1, 2)}.`); // 1 + 2 = 3.
バッククォートを使用するもう一つの利点は、文字列を複数行にまたがって記述できることです。
let guestList = `Guests:
* John
* Pete
* Mary
`;
alert(guestList); // a list of guests, multiple lines
自然に見えますよね?しかし、シングルクォートやダブルクォートではこのように動作しません。
これらを使用し、複数行にまたがって記述しようとするとエラーが発生します。
let guestList = "Guests: // Error: Unexpected token ILLEGAL
* John";
シングルクォートとダブルクォートは、複数行の文字列の必要性が考慮されていなかった、言語作成の古い時代に登場しました。バッククォートは後になって登場したため、より多用途です。
バッククォートでは、最初のバッククォートの前に「テンプレート関数」を指定することもできます。構文はfunc`string`
です。関数func
は自動的に呼び出され、文字列と埋め込まれた式を受け取り、それらを処理できます。この機能は「タグ付きテンプレート」と呼ばれ、めったに見られませんが、MDNで詳しく読むことができます: テンプレートリテラル。
特殊文字
いわゆる「改行文字」である\n
を使用することで、シングルクォートやダブルクォートでも複数行の文字列を作成することができます。これは改行を表します。
let guestList = "Guests:\n * John\n * Pete\n * Mary";
alert(guestList); // a multiline list of guests, same as above
より簡単な例として、以下の2行は、記述方法が異なるだけで、同じです。
let str1 = "Hello\nWorld"; // two lines using a "newline symbol"
// two lines using a normal newline and backticks
let str2 = `Hello
World`;
alert(str1 == str2); // true
他にも、あまり一般的ではない特殊文字があります。
文字 | 説明 |
---|---|
\n |
改行 |
\r |
Windowsのテキストファイルでは、2つの文字\r\n の組み合わせが新しい改行を表しますが、Windows以外のOSでは\n のみです。これは歴史的な理由によるもので、ほとんどのWindowsソフトウェアも\n を理解します。 |
\' , \" , \` |
引用符 |
\\ |
バックスラッシュ |
\t |
タブ |
\b , \f , \v |
バックスペース、フォームフィード、垂直タブ - 完全性のために言及しましたが、古い時代のもので、最近では使用されません(今すぐ忘れても構いません)。 |
ご覧のとおり、すべての特殊文字はバックスラッシュ文字\
で始まります。これは「エスケープ文字」とも呼ばれます。
これは非常に特殊であるため、文字列内に実際のバックスラッシュ\
を表示する必要がある場合は、それを2倍にする必要があります。
alert( `The backslash: \\` ); // The backslash: \
いわゆる「エスケープされた」引用符\'
、\"
、\`
は、同じ引用符で囲まれた文字列内に引用符を挿入するために使用されます。
例えば
alert( 'I\'m the Walrus!' ); // I'm the Walrus!
ご覧のとおり、内側の引用符はバックスラッシュ\'
で前置する必要があります。そうしないと、文字列の終わりを示すことになってしまうからです。
もちろん、エスケープする必要があるのは、囲んでいる引用符と同じ引用符だけです。したがって、よりエレガントな解決策として、代わりにダブルクォートまたはバッククォートに切り替えることができます。
alert( "I'm the Walrus!" ); // I'm the Walrus!
これらの特殊文字に加えて、Unicodeコード\u…
の特殊な表記法もあります。これはめったに使用されず、Unicodeに関するオプションの章で説明します。
文字列の長さ
length
プロパティは文字列の長さを持っています。
alert( `My\n`.length ); // 3
\n
は単一の「特殊」文字であるため、長さは確かに3
であることに注意してください。
length
はプロパティです他の言語のバックグラウンドを持つ人は、str.length
の代わりにstr.length()
とタイプミスすることがあります。これは機能しません。
str.length
は数値プロパティであり、関数ではないことに注意してください。後に括弧を追加する必要はありません。.length()
ではなく、.length
です。
文字へのアクセス
位置pos
の文字を取得するには、角かっこ[pos]
を使用するか、str.at(pos)メソッドを呼び出します。最初の文字はゼロの位置から始まります。
let str = `Hello`;
// the first character
alert( str[0] ); // H
alert( str.at(0) ); // H
// the last character
alert( str[str.length - 1] ); // o
alert( str.at(-1) );
ご覧のとおり、.at(pos)
メソッドには負のポジションを許可するという利点があります。pos
が負の場合、文字列の末尾から数えられます。
したがって、.at(-1)
は最後の文字を意味し、.at(-2)
はその前の文字などとなります。
角かっこは、負のインデックスに対して常にundefined
を返します。例えば
let str = `Hello`;
alert( str[-2] ); // undefined
alert( str.at(-2) ); // l
for..of
を使用して文字を反復処理することもできます。
for (let char of "Hello") {
alert(char); // H,e,l,l,o (char becomes "H", then "e", then "l" etc)
}
文字列は不変です
JavaScriptでは、文字列は変更できません。文字を変更することは不可能です。
それが機能しないことを示すために試してみましょう。
let str = 'Hi';
str[0] = 'h'; // error
alert( str[0] ); // doesn't work
通常の回避策は、古い文字列の代わりに新しい文字列を作成し、それをstr
に割り当てることです。
例えば
let str = 'Hi';
str = 'h' + str[1]; // replace the string
alert( str ); // hi
次のセクションでは、この例をさらに見ていきます。
大文字と小文字の変更
toLowerCase()メソッドとtoUpperCase()メソッドは大文字と小文字を変更します。
alert( 'Interface'.toUpperCase() ); // INTERFACE
alert( 'Interface'.toLowerCase() ); // interface
または、単一の文字を小文字にしたい場合
alert( 'Interface'[0].toLowerCase() ); // 'i'
部分文字列の検索
文字列内で部分文字列を検索する方法は複数あります。
str.indexOf
最初のメソッドは、str.indexOf(substr, pos)です。
与えられた位置pos
から開始して、str
内でsubstr
を探し、一致が見つかった位置を返します。何も見つからない場合は-1
を返します。
例えば
let str = 'Widget with id';
alert( str.indexOf('Widget') ); // 0, because 'Widget' is found at the beginning
alert( str.indexOf('widget') ); // -1, not found, the search is case-sensitive
alert( str.indexOf("id") ); // 1, "id" is found at the position 1 (..idget with id)
オプションの2番目のパラメータを使用すると、指定された位置から検索を開始できます。
例えば、"id"
の最初の一致は位置1
にあります。次の一致を探すには、位置2
から検索を開始しましょう。
let str = 'Widget with id';
alert( str.indexOf('id', 2) ) // 12
すべての一致に関心がある場合は、ループでindexOf
を実行できます。新しい呼び出しは、前のマッチ後の位置で行われます。
let str = 'As sly as a fox, as strong as an ox';
let target = 'as'; // let's look for it
let pos = 0;
while (true) {
let foundPos = str.indexOf(target, pos);
if (foundPos == -1) break;
alert( `Found at ${foundPos}` );
pos = foundPos + 1; // continue the search from the next position
}
同じアルゴリズムをより短くレイアウトできます。
let str = "As sly as a fox, as strong as an ox";
let target = "as";
let pos = -1;
while ((pos = str.indexOf(target, pos + 1)) != -1) {
alert( pos );
}
str.lastIndexOf(substr, position)
文字列の末尾から先頭に向かって検索する同様のメソッドstr.lastIndexOf(substr, position)もあります。
逆順で一致をリストします。
if
テストでindexOf
を使用すると、わずかな不便さがあります。このようにif
に入れることはできません。
let str = "Widget with id";
if (str.indexOf("Widget")) {
alert("We found it"); // doesn't work!
}
上記の例のalert
は表示されません。なぜなら、str.indexOf("Widget")
は0
を返す(開始位置で一致が見つかったことを意味する)からです。その通りですが、if
は0
をfalse
と見なします。
したがって、実際にはこのように-1
をチェックする必要があります。
let str = "Widget with id";
if (str.indexOf("Widget") != -1) {
alert("We found it"); // works now!
}
includes、startsWith、endsWith
よりモダンなメソッドstr.includes(substr, pos)は、str
にsubstr
が含まれているかどうかに応じて、true/false
を返します。
一致をテストする必要があるが、その位置は必要ない場合に適切な選択です。
alert( "Widget with id".includes("Widget") ); // true
alert( "Hello".includes("Bye") ); // false
str.includes
のオプションの2番目の引数は、検索を開始する位置です。
alert( "Widget".includes("id") ); // true
alert( "Widget".includes("id", 3) ); // false, from position 3 there is no "id"
str.startsWithメソッドとstr.endsWithメソッドは、その名前が示すとおりに動作します。
alert( "Widget".startsWith("Wid") ); // true, "Widget" starts with "Wid"
alert( "Widget".endsWith("get") ); // true, "Widget" ends with "get"
部分文字列の取得
JavaScriptで部分文字列を取得する方法は3つあります: substring
、substr
、slice
。
str.slice(start [, end])
-
文字列の
start
からend
(ただし、end
は含まない)までの部分を返します。例えば
let str = "stringify"; alert( str.slice(0, 5) ); // 'strin', the substring from 0 to 5 (not including 5) alert( str.slice(0, 1) ); // 's', from 0 to 1, but not including 1, so only character at 0
2番目の引数がない場合、
slice
は文字列の末尾まで続きます。let str = "stringify"; alert( str.slice(2) ); // 'ringify', from the 2nd position till the end
start/end
に負の値も可能です。これは、位置が文字列の末尾から数えられることを意味します。let str = "stringify"; // start at the 4th position from the right, end at the 1st from the right alert( str.slice(-4, -1) ); // 'gif'
str.substring(start [, end])
-
start
とend
の間(end
は含まない)の文字列の部分を返します。これは
slice
とほぼ同じですが、start
がend
よりも大きくなることを許可します(この場合、単にstart
とend
の値を入れ替えます)。例えば
let str = "stringify"; // these are same for substring alert( str.substring(2, 6) ); // "ring" alert( str.substring(6, 2) ); // "ring" // ...but not for slice: alert( str.slice(2, 6) ); // "ring" (the same) alert( str.slice(6, 2) ); // "" (an empty string)
(sliceとは異なり)負の引数はサポートされておらず、
0
として扱われます。 str.substr(start [, length])
-
与えられた
length
で、start
からの文字列の部分を返します。前のメソッドとは対照的に、このメソッドでは終了位置の代わりに
length
を指定できます。let str = "stringify"; alert( str.substr(2, 4) ); // 'ring', from the 2nd position get 4 characters
最初の引数は、末尾から数えるために負の値を指定できます。
let str = "stringify"; alert( str.substr(-4, 2) ); // 'gi', from the 4th position get 2 characters
このメソッドは、言語仕様のAnnex Bに記載されています。つまり、ブラウザでホストされたJavaScriptエンジンのみがサポートすべきであり、使用は推奨されません。実際には、どこでもサポートされています。
混乱を避けるため、これらのメソッドをまとめておきましょう。
メソッド | 選択… | 負数 |
---|---|---|
slice(start, end) |
start からend まで(end は含まない) |
負数を許可 |
substring(start, end) |
start とend の間(end は含まない) |
負数は0 を意味する |
substr(start, length) |
start からlength 文字を取得 |
負のstart を許可 |
どれでも同じことができます。形式的には、substr
にはわずかな欠点があります。JavaScriptのコア仕様ではなく、主に歴史的な理由で存在するブラウザ限定の機能をカバーするAnnex Bに記述されていることです。そのため、ブラウザ以外の環境ではサポートされない可能性があります。しかし、実際にはどこでも動作します。
他の2つの選択肢のうち、slice
は少し柔軟性があり、負の引数を許可し、記述も短くて済みます。
したがって、実用上はslice
だけを覚えておけば十分です。
文字列の比較
比較の章で説明したように、文字列はアルファベット順に文字ごとに比較されます。
ただし、いくつかの奇妙な点があります。
-
小文字は常に大文字よりも大きい
alert( 'a' > 'Z' ); // true
-
発音区別記号付きの文字は「順不同」である
alert( 'Österreich' > 'Zealand' ); // true
これにより、これらの国名をソートすると奇妙な結果になる可能性があります。通常、人々はリストで
Zealand
がÖsterreich
の後に来ることを期待するでしょう。
何が起こっているかを理解するために、JavaScriptの文字列がUTF-16を使用してエンコードされていることを知っておく必要があります。つまり、各文字には対応する数値コードがあります。
コードから文字を取得したり、その逆を行ったりするための特別なメソッドがあります。
str.codePointAt(pos)
-
位置
pos
の文字のコードを表す10進数を返します// different case letters have different codes alert( "Z".codePointAt(0) ); // 90 alert( "z".codePointAt(0) ); // 122 alert( "z".codePointAt(0).toString(16) ); // 7a (if we need a hexadecimal value)
String.fromCodePoint(code)
-
数値
code
で文字を作成しますalert( String.fromCodePoint(90) ); // Z alert( String.fromCodePoint(0x5a) ); // Z (we can also use a hex value as an argument)
それでは、コード65..220
(ラテンアルファベットと少し追加)を持つ文字を、それらの文字列を作成して見てみましょう。
let str = '';
for (let i = 65; i <= 220; i++) {
str += String.fromCodePoint(i);
}
alert( str );
// Output:
// ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
// ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜ
見てください。大文字が最初に来て、いくつかの特殊文字、次に小文字、そして出力の最後近くにÖ
があります。
これで、なぜa > Z
なのかが明らかになりました。
文字は数値コードによって比較されます。コードが大きいほど、文字が大きくなります。a
(97)のコードは、Z
(90)のコードよりも大きいです。
- すべての小文字は、コードが大きいため、大文字の後に来ます。
Ö
のような一部の文字は、メインのアルファベットから離れて立っています。ここでは、コードがa
からz
までのどれよりも大きいです。
正しい比較
文字列比較を行う「正しい」アルゴリズムは、言語によってアルファベットが異なるため、思ったよりも複雑です。
そのため、ブラウザは比較する言語を知る必要があります。
幸いなことに、最新のブラウザは国際化標準ECMA-402をサポートしています。
これは、言語の規則に従って、異なる言語で文字列を比較するための特別なメソッドを提供します。
str.localeCompare(str2)
を呼び出すと、言語規則に従ってstr
がstr2
よりも小さいか、等しいか、大きいかを示す整数が返されます。
str
がstr2
より小さい場合は負の数を返します。str
がstr2
より大きい場合は正の数を返します。- 等しい場合は
0
を返します。
例えば
alert( 'Österreich'.localeCompare('Zealand') ); // -1
このメソッドには、ドキュメントで指定されている2つの追加引数があり、言語(デフォルトでは環境から取得、文字順は言語に依存)を指定したり、大文字と小文字の区別や、"a"
と"á"
を同じものとして扱うべきかなどの追加ルールを設定したりできます。
まとめ
- 引用符には3つのタイプがあります。バッククォートを使用すると、文字列を複数行にまたがらせたり、式
${…}
を埋め込んだりできます。 - 改行
\n
などの特殊文字を使用できます。 - 文字を取得するには、
[]
またはat
メソッドを使用します。 - 部分文字列を取得するには、
slice
またはsubstring
を使用します。 - 文字列を小文字/大文字にするには、
toLowerCase/toUpperCase
を使用します。 - 部分文字列を検索するには、
indexOf
、または単純なチェックの場合はincludes/startsWith/endsWith
を使用します。 - 言語に従って文字列を比較するには、
localeCompare
を使用します。それ以外の場合は、文字コードによって比較されます。
文字列には、他にも役立つメソッドがいくつかあります。
str.trim()
– 文字列の先頭と末尾のスペースを削除(「トリミング」)します。str.repeat(n)
– 文字列をn
回繰り返します。- …およびマニュアルに記載されているその他。
文字列には、正規表現を使用した検索/置換を行うためのメソッドもあります。しかし、それは大きなトピックなので、別のチュートリアルセクション正規表現で説明します。
また、現在では、文字列がUnicodeエンコーディングに基づいているため、比較に問題があることを知っておくことが重要です。Unicodeの詳細については、Unicode、文字列の内部の章で説明します。
コメント
<code>
タグを使用し、数行の場合は<pre>
タグでラップし、10行を超える場合はサンドボックス(plnkr、jsbin、codepen…)を使用してください。