第12章 文字列
目次
書籍を購入する
(広告です。ブロックしないでください。)

第12章 文字列

文字列は、JavaScriptの文字の不変シーケンスです。各文字は16ビットのUTF-16コードユニットです。つまり、単一のUnicode文字は、1つまたは2つのJavaScript文字で表されます。文字を数えたり、文字列を分割したりする場合に、2文字の場合を考慮する必要があります(第24章を参照)。

文字列リテラル

単一引用符と二重引用符の両方を使用して、文字列リテラルを区切ることができます。

'He said: "Hello"'
"He said: \"Hello\""

'Everyone\'s a winner'
"Everyone's a winner"

したがって、どちらの種類の引用符も自由に使用できます。ただし、いくつかの考慮事項があります。

  • コミュニティで最も一般的なスタイルは、HTMLには二重引用符、JavaScriptには単一引用符を使用することです。
  • 一方、一部の言語(CやJavaなど)では、文字列には二重引用符のみが使用されます。したがって、多言語コードベースでは二重引用符を使用するのが理にかなっている場合があります。
  • JSON(第22章で説明)では、二重引用符を使用する必要があります。

一貫して引用符を使用すると、コードが見やすくなります。ただし、異なる引用符を使用することでエスケープを回避できる場合があり、一貫性をそれほど重視しなくても済む場合があります(たとえば、通常は単一引用符を使用しますが、上記の最後の例を書くために一時的に二重引用符に切り替える場合があります)。

文字列リテラルのエスケープ

文字列リテラルのほとんどの文字は、単にそれ自体を表します。バックスラッシュはエスケープに使用され、いくつかの特別な機能を有効にします。

行の継続

行末(行末文字、行ターミネータ)をバックスラッシュでエスケープすることにより、文字列を複数行に展開できます。

var str = 'written \
over \
multiple \
lines';
console.log(str === 'written over multiple lines'); // true

代わりに、プラス演算子を使用して連結することもできます。

var str = 'written ' +
          'over ' +
          'multiple ' +
          'lines';
文字エスケープシーケンス

これらのシーケンスはバックスラッシュで始まります。

  • 制御文字:\bはバックスペース、\fはフォームフィード、\nは改行、\rは復帰、\tは水平タブ、\vは垂直タブです。
  • それ自体を表すエスケープされた文字:\'は単一引用符、\"は二重引用符、\\はバックスラッシュです。b f n r t v x uと10進数字以外のすべての文字もそれ自体を表します。次に2つの例を示します。

    > '\"'
    '"'
    > '\q'
    'q'
NUL文字(Unicodeコードポイント0)
この文字は\0で表されます。
16進エスケープシーケンス

\xHHHHは2つの16進数字)は、ASCIIコードを介して文字を指定します。例えば:

> '\x4D'
'M'
Unicodeエスケープシーケンス

\uHHHHHHHHは4つの16進数字)は、UTF-16コードユニットを指定します(第24章を参照)。次に2つの例を示します。

> '\u004D'
'M'
> '\u03C0'
'π'

文字アクセス

文字列のn番目の文字を返す操作は2つあります。[16] JavaScriptには文字用の特別なデータ型がないことに注意してください。これらの操作は文字列を返します。

> 'abc'.charAt(1)
'b'
> 'abc'[1]
'b'

一部の古いブラウザでは、角括弧による文字への配列のようなアクセスはサポートされていません。

文字列への変換

値は次のように文字列に変換されます。

結果

undefined

'undefined'

null

'null'

真偽値

false'false'

true'true'

数値

文字列としての数値(例:3.141'3.141'

文字列

入力と同じ(変換するものがない)

オブジェクト

ToPrimitive(value, String)を呼び出し(アルゴリズム:ToPrimitive()—値をプリミティブに変換するを参照)、結果のプリミティブを変換します。

手動での文字列への変換

任意の値を文字列に変換する最も一般的な3つの方法は次のとおりです。

String(value)

(コンストラクターとしてではなく、関数として呼び出されます)

''+value

value.toString()

undefinednullでは機能しません!)

より記述的なので、String()の方が好きです。次にいくつかの例を示します。

> String(false)
'false'
> String(7.35)
'7.35'
> String({ first: 'John', last: 'Doe' })
'[object Object]'
> String([ 'a', 'b', 'c' ])
'a,b,c'

データを表示する場合、JSON.stringify()JSON.stringify(value, replacer?, space?))の方が標準の文字列変換よりも効果的な場合があります。

> console.log(JSON.stringify({ first: 'John', last: 'Doe' }))
{"first":"John","last":"Doe"}
> console.log(JSON.stringify([ 'a', 'b', 'c' ]))
["a","b","c"]

当然のことながら、JSON.stringify()の制限事項に注意する必要があります。すべてが表示されるわけではありません。たとえば、処理できない値(関数など)のプロパティは非表示になります。プラス面としては、その出力はeval()によって解析でき、深くネストされたデータをきれいにフォーマットされたツリーとして表示できます。

落とし穴:変換は可逆的ではありません

JavaScriptが自動的に変換を行う頻度を考えると、変換が常に可逆的ではないのは残念です。特に真偽値に関しては:

> String(false)
'false'
> Boolean('false')
true

undefinednullについても、同様の問題が発生します。

文字列の比較

文字列を比較するには2つの方法があります。まず、比較演算子を使用できます:<>===<=>=これらには次の欠点があります。

  • 大文字と小文字が区別されます

    > 'B' > 'A'  // ok
    true
    > 'B' > 'a'  // should be true
    false
  • ウムラウトとアクセントがうまく処理されません

    > 'ä' < 'b'  // should be true
    false
    > 'é' < 'f'  // should be true
    false

2つ目に、String.prototype.localeCompare(other)を使用できます。これはより良い結果をもたらす傾向がありますが、常にサポートされているわけではありません(検索と比較を参照して詳細を確認してください)。 Firefoxのコンソールでの操作例を以下に示します。

> 'B'.localeCompare('A')
2
> 'B'.localeCompare('a')
2

> 'ä'.localeCompare('b')
-2
> 'é'.localeCompare('f')
-2

結果が0未満の場合、レシーバーは引数よりも「小さい」ことを意味します。結果が0より大きい場合、レシーバーは引数よりも「大きい」ことを意味します。

文字列の連結

文字列を連結するには、主に2つの方法があります。

連結:プラス(+)演算子

演算子+は、オペランドの1つが文字列になるとすぐに文字列連結を実行します。文字列の断片を変数に収集する場合は、複合代入演算子+=が便利です。

> var str = '';
> str += 'Say hello ';
> str += 7;
> str += ' times fast!';
> str
'Say hello 7 times fast!'

関数String

関数Stringは、2つの方法で呼び出すことができます。

String(value)

通常の関数として、valueをプリミティブ文字列に変換します(文字列への変換を参照)。

> String(123)
'123'
> typeof String('abc')  // no change
'string'
new String(str)

コンストラクターとして、Stringの新しいインスタンス(プリミティブのラッパーオブジェクトを参照)を作成します。これは、strをラップするオブジェクトです(文字列以外は文字列に強制されます)。例えば

> typeof new String('abc')
'object'

前者の呼び出しが一般的です。

Stringコンストラクターメソッド

String.fromCharCode(codeUnit1, codeUnit2, ...)は、文字が16ビット符号なし整数codeUnit1codeUnit2などで指定されたUTF-16コードユニットである文字列を生成します。例えば:

> String.fromCharCode(97, 98, 99)
'abc'

数値の配列を文字列に変換する場合は、apply()func.apply(thisValue, argArray)を参照)を使用して行うことができます。

> String.fromCharCode.apply(null, [97, 98, 99])
'abc'

String.fromCharCode()逆はString.prototype.charCodeAt()です。

Stringインスタンスプロパティlength

lengthプロパティは、文字列内のJavaScript文字の数を示し、不変です。

> 'abc'.length
3

Stringプロトタイプメソッド

プリミティブ文字列のすべてのメソッドは、String.prototypeに格納されます(プリミティブはラッパーからメソッドを借用するを参照)。次に、Stringのインスタンスではなく、プリミティブ文字列でどのように機能するかを説明します。

部分文字列の抽出

次のメソッドは、レシーバーから部分文字列を抽出します。

String.prototype.charAt(pos)

位置posにある文字を含む文字列を返します。例えば:

> 'abc'.charAt(1)
'b'

次の2つの式は同じ結果を返しますが、一部の古いJavaScriptエンジンは文字にアクセスするためにcharAt()のみをサポートしています。

str.charAt(n)
str[n]
String.prototype.charCodeAt(pos)

位置posにあるJavaScript文字(UTF-16コードユニット、第24章を参照)のコード(16ビット符号なし整数)を返します。

文字コードの配列を作成する方法は次のとおりです。

> 'abc'.split('').map(function (x) { return x.charCodeAt(0) })
[ 97, 98, 99 ]

charCodeAt()の逆はString.fromCharCode()です。

String.prototype.slice(start, end?)

位置startから位置endまで(endは含まない)の部分文字列を返します。2つのパラメーターはどちらも負の値にすることができ、その場合、文字列のlengthがそれらに追加されます。

> 'abc'.slice(2)
'c'
> 'abc'.slice(1, 2)
'b'
> 'abc'.slice(-2)
'bc'
String.prototype.substring(start, end?)
これはslice()に似ていますが、負の位置を処理でき、ブラウザ間でより一貫性のある実装になっているため、slice()を優先して使用することをお勧めします。
String.prototype.split(separator?, limit?)

separatorで区切られたレシーバーの部分文字列を抽出し、それらを配列で返します。このメソッドには2つのパラメーターがあります。

  • separator:文字列または正規表現。指定しない場合、文字列全体が配列にラップされて返されます。
  • limit:指定した場合、返される配列には最大limit個の要素が含まれます。

次にいくつかの例を示します。

> 'a,  b,c, d'.split(',')  // string
[ 'a', '  b', 'c', ' d' ]
> 'a,  b,c, d'.split(/,/)  // simple regular expression
[ 'a', '  b', 'c', ' d' ]
> 'a,  b,c, d'.split(/, */)   // more complex regular expression
[ 'a', 'b', 'c', 'd' ]
> 'a,  b,c, d'.split(/, */, 2)  // setting a limit
[ 'a', 'b' ]
> 'test'.split()  // no separator provided
[ 'test' ]

グループがある場合、一致も配列要素として返されます。

> 'a,  b  ,  '.split(/(,)/)
[ 'a', ',', '  b  ', ',', '  ' ]
> 'a,  b  ,  '.split(/ *(,) */)
[ 'a', ',', 'b', ',', '' ]

文字列の文字を含む配列を生成するには、''(空の文字列)を区切り文字として使用します。

> 'abc'.split('')
[ 'a', 'b', 'c' ]

変換

前のセクションは部分文字列の抽出についてでしたが、このセクションでは、与えられた文字列を新しい文字列に変換する方法について説明します。 これらのメソッドは、通常、次のように使用されます。

var str = str.trim();

つまり、元の文字列は(非破壊的に)変換された後に破棄されます。

String.prototype.trim()

文字列の先頭と末尾からすべての空白文字を削除します。

> '\r\nabc \t'.trim()
'abc'
String.prototype.concat(str1?, str2?, ...)

レシーバーと`str1`、`str2`などを連結したものを返します。

> 'hello'.concat(' ', 'world', '!')
'hello world!'
String.prototype.toLowerCase()

元の文字列のすべての文字を小文字に変換した新しい文字列を作成します。

> 'MJÖLNIR'.toLowerCase()
'mjölnir'
String.prototype.toLocaleLowerCase()
`toLowerCase()`と同じように動作しますが、現在のロケールのルールを考慮します。ECMAScript仕様によると、「その言語のルールが通常のUnicode大文字小文字マッピングと競合する場合(トルコ語など)、違いが生じるのはごく少数の場合のみです。」
String.prototype.toUpperCase()

元の文字列のすべての文字を大文字に変換した新しい文字列を作成します。

> 'mjölnir'.toUpperCase()
'MJÖLNIR'
String.prototype.toLocaleUpperCase()
`toUpperCase()`と同じように動作しますが、現在のロケールのルールを考慮します。

検索と比較

以下のメソッドは、文字列の検索と比較に使用されます。

String.prototype.indexOf(searchString, position?)

`position`(デフォルトは0)から始まる`searchString`を検索します。 `searchString`が見つかった位置を返します。見つからない場合は-1を返します。

> 'aXaX'.indexOf('X')
1
> 'aXaX'.indexOf('X', 2)
3

文字列内のテキストを見つける場合、正規表現も同様に機能することに注意してください。たとえば、次の2つの式は同等です。

str.indexOf('abc') >= 0
/abc/.test(str)
String.prototype.lastIndexOf(searchString, position?)

`position`(デフォルトは末尾)から開始して、`searchString`を逆方向に検索します。 `searchString`が見つかった位置、または見つからない場合は-1を返します。

> 'aXaX'.lastIndexOf('X')
3
> 'aXaX'.lastIndexOf('X', 2)
1
String.prototype.localeCompare(other)

文字列と`other`をロケールに依存した比較を実行します。次の数値を返します。

  • 文字列が`other`の前にある場合は< 0
  • 文字列が`other`と同等の場合は= 0
  • 文字列が`other`の後にある場合は> 0

例えば

> 'apple'.localeCompare('banana')
-2
> 'apple'.localeCompare('apple')
0

警告

すべてのJavaScriptエンジンがこのメソッドを正しく実装しているわけではありません。比較演算子に基づいているものもあります。ただし、ECMAScript Internationalization API(ECMAScript国際化APIを参照)は、Unicodeを認識した実装を提供しています。つまり、そのAPIがエンジンで利用可能な場合、`localeCompare()`は機能します。

サポートされている場合、`localeCompare()`は比較演算子よりも文字列を比較するのに適しています。詳細については、文字列の比較を参照してください。

正規表現によるテスト、マッチ、置換

以下のメソッドは正規表現で動作します。

`String.prototype.search(regexp)`(String.prototype.search: 一致するインデックスは?で詳しく説明されています)

レシーバー内で`regexp`が一致する最初のインデックスを返します(一致しない場合は-1)。

> '-yy-xxx-y-'.search(/x+/)
4
`String.prototype.match(regexp)`(String.prototype.match: キャプチャグループまたはすべての一致する部分文字列を返すで詳しく説明されています)

レシーバーに対して指定された正規表現を照合します。 `regexp`のフラグ`/g`が設定されていない場合、最初の一致に対して一致オブジェクトを返します。

> '-abb--aaab-'.match(/(a+)b/)
[ 'ab',
  'a',
  index: 1,
  input: '-abb--aaab-' ]

フラグ`/g`が設定されている場合、すべての一致(グループ0)が配列で返されます。

> '-abb--aaab-'.match(/(a+)b/g)
[ 'ab', 'aaab' ]
`String.prototype.replace(search, replacement)`(で詳しく説明されていString.prototype.replace: 検索と置換ます)

`search`を検索し、`replacement`で置き換えます。 `search`は文字列または正規表現にすることができ、`replacement`は文字列または関数にすることができます。フラグ`/g`が設定された正規表現を`search`として使用しない限り、最初に出現したものだけが置き換えられます。

> 'iixxxixx'.replace('i', 'o')
'oixxxixx'
> 'iixxxixx'.replace(/i/, 'o')
'oixxxixx'
> 'iixxxixx'.replace(/i/g, 'o')
'ooxxxoxx'

置換文字列内のドル記号(`$`)を使用すると、完全一致またはキャプチャされたグループを参照できます。

> 'iixxxixx'.replace(/i+/g, '($&)') // complete match
'(ii)xxx(i)xx'
> 'iixxxixx'.replace(/(i+)/g, '($1)') // group 1
'(ii)xxx(i)xx'

関数を使用して置換を計算することもできます。

> function repl(all) { return '('+all.toUpperCase()+')' }
> 'axbbyyxaa'.replace(/a+|b+/g, repl)
'(A)x(BB)yyx(AA)'



[16] 厳密に言うと、JavaScriptの文字列はUTF-16コードユニットのシーケンスで構成されています。つまり、JavaScriptの文字はUnicodeコードユニットです(第24章を参照)。

次: 13. ステートメント