JavaScriptでは、文字列はUTF-16で表現される文字の集合として管理されます。
JavaScriptにはCやC++のような文字型という概念はなく、すべて文字列として扱われます。
文字列は単一引用符 (') または二重引用符 (") で囲んで表現します。いずれの引用符を使用するかは任意であり、意味の違いはありません。
エスケープシーケンスを利用することで、特殊な文字を文字列リテラルに記述できます。いずれもバックスラッシュ ( \
) に続ける形式で記述します。
シーケンス | 説明 |
---|---|
\' |
シングルクォーテーション (単一引用符) [\u0027 ] |
\" |
ダブルクォーテーション (二重引用符) [\u0022 ] |
\\ |
バックスラッシュ [\u005C ] |
\xXX |
Latin-1文字 (2桁の16進数で指定) |
\XXX |
Latin-1文字 (3桁の8進数で指定) (非推奨) |
\uXXXX ※1 |
Unicode文字 (4桁の16進数で指定) |
※1 この形式がサポートされるのはJavaScript 1.3以降です。また任意の文字の\uXXXX
の形式は、エンコードすることで調べられます。
文字列リテラルはStringオブジェクトではないため、
'a' instanceof String
はtrueとはなりません。 文字列リテラルは String オブジェクトとは別物 - MDN
評価方法 | サンプルコード | 評価結果 |
---|---|---|
instanceof | 'a' instanceof String |
false |
new String( 'a' ) instanceof String |
true |
|
typeof | typeof 'a' |
"string" |
typeof new String( 'a' ) |
"object" |
文字列リテラルの途中で改行してはなりません。
var str = 'ABC // ここでエラー
DEF;
これは「終了していない文字列型の定数です。」「SyntaxError: unterminated string literal」のようなエラーとなります。
同じ表現をするならば、エスケープシーケンスの\n
を用いて
var str = 'ABC\nDEF;
とします。ちなみにPHPではリテラルの途中での改行が認められており、改行文字がそのまま文字列の一部となります。
var n = string - 0;
var n = Number( string );
var n = parseInt( string, 10 );
var n = parseFloat( string );
これらの方法で結果がどのように異なるかを、下表にまとめます。試行したのは次の5種類の文字列です。
変換方法 | (1) '10' |
(2) '1.5' |
(3) '0x10' |
(4) '10a' |
(5) 'a10' |
---|---|---|---|---|---|
文字列 - 0 | 10 |
1.5 |
16 |
NaN |
NaN |
Number() | |||||
parseInt() | 1 |
10 |
|||
parseFloat() | 1.5 |
0 |
var s = number + '';
var s = String( number );
var s = number.toString( 10 );
var s = number.toFixed( 3 );
var s = number.toExponential( 3 );
var s = number.toPrecision( 3 );
( 10 ).toString( 2 ); // "1010" ( 10 ).toString( 10 ); // "10" ( 10 ).toString( 16 ); // "a"
toFixed()などのメソッドでは、数値を整形して出力できます。
( 10.25 ).toFixed( 0 ); // "10" ( 10.25 ).toFixed( 1 ); // "10.3" ※丸められている ( 10.25 ).toFixed( 2 ); // "10.25" ( 10.25 ).toFixed( 3 ); // "10.250" ( 10.25 ).toExponential( 0 ); // "1e+1" ( 10.25 ).toExponential( 1 ); // "1.0e+1" ( 10.25 ).toExponential( 2 ); // "1.03e+1" ( 10.25 ).toExponential( 3 ); // "1.025e+1" ( 10.25 ).toPrecision( 0 ); // RangeError: precision 0 out of range ( 10.25 ).toPrecision( 1 ); // "1e+1" ( 10.25 ).toPrecision( 2 ); // "10" ( 10.25 ).toPrecision( 3 ); // "10.3" ( 10.25 ).toPrecision( 4 ); // "10.25"
プロパティ | 内容 |
---|---|
length | 文字列内の文字数 |
分類 | メソッド | 説明 |
---|---|---|
出現位置 | indexOf | 文字列の出現位置を先頭から検索 |
lastIndexOf | 文字列の出現位置を後方から検索 | |
取得 | charAt | 指定された位置の文字を取得 |
slice | 文字列の一部を取得 | |
substr | 文字列の一部を取得 [非推奨] | |
substring | 文字列の一部を取得 | |
正規表現 | match | 正規表現に一致する文字列を取得 |
search | 正規表現に一致する文字列の出現位置を検索 | |
replace | 正規表現または文字列に一致する文字列を置換 | |
連結 | concat | 文字列に1つ以上の値を連結 |
分割 | split | 区切り文字列か正規表現で区切り、文字列の配列に分割 |
大文字/小文字 | toLowerCase | すべての文字を小文字に変換した文字列を取得 |
toUpperCase | すべての文字を大文字に変換した文字列を取得 | |
比較 | localeCompare | ロケール特有の順序で文字列を比較 |
エンコーディング | charCodeAt | 指定された位置の文字のエンコーディングを取得 |
toString | 基本型の文字列値を取得 | |
valueOf | 基本型の文字列値を取得 |
これ以外にも文字列をエスケープ (エンコード) する関数が、グローバル関数に定義されています。
Stringオブジェクトは他のオブジェクトと同様に、コンストラクタにnew演算子を付けて生成します。
var s = new String( 'abc' );
new演算子を省略して、
var s = String( 'abc' );
としたり、または引用符で囲んで
var s = 'abc';
とすることでも文字列を生成できますが、これらはデータ型としての文字列であって、Stringオブジェクトではありません。このことはtypeof演算子で確認できます。
typeof new String( 'abc' ); // "object" が返される typeof String( 'abc' ); // "string"
ただしJavaScriptの文字列はStringオブジェクトのメソッドなどへアクセスできるため、
'abc'.split( '' );
のように、文字列からメソッドを呼び出せます。
new String( 'abc' ).length; // 3 が返される new String( 'あいう' ).length; // 3
コードポイントが0x010000以降の文字はサロゲートペアにより4バイトで表現されるため、返される文字数が2倍になります。
new String( '🚀🚁🚂' ).length; // 6 が返される
Stringオブジェクトから、指定位置の文字を返します。
String.charAt( index )
取得位置をindexで指定します。
new String( 'abc' ).charAt( 1 ); // 'b' が返される new String( 'あいう' ).charAt( 1 ); // 'い'
サロゲートペアで表現される文字は上位または下位のサロゲートが返されることになり、その結果REPLACEMENT CHARACTER「�」(U+FFFD) の文字か、そのコードとなります。
new String( '🚀🚁🚂' ).charAt( 1 ); // '�' または '\ude80' が返される
Stringオブジェクトに配列のようにアクセスすると、指定位置の文字を取得できる環境もあります。しかしこれは非標準な方法のため、使用を避けるべきです。
var str = new String( 'abc' ); var a = str[ 1 ]; // 'b' が返される var b = str.charAt( 1 ); // 'b'文字へのアクセス - String - JavaScript | MDN
String.slice( beginslice[, endSlice] );String.prototype.slice - JavaScript | MDN
beginsliceの位置から、endSliceの直前までの文字列を取り出します。
String.substring( indexA[, indexB] )String.substring - JavaScript | MDN
indexAの位置から、indexBの直前までの文字列を取り出します。
slice | substring |
---|---|
var str = new String( '01234' ); str.slice(0,3); // '012' str.slice(1,3); // '12' str.slice(3,1); // '' str.slice(3,-1); // '3' str.slice(3,0); // '' str.slice(0); // '01234' str.slice(1); // '1234' str.slice(3); // '34' str.slice(1,1); // '' str.slice(-1); // '4' str.slice(-3); // '234' str.slice(-3,3); // '2' str.slice(-3,-1); // '23' str.slice(-1,3); // '' str.slice(10); // '' str.slice(0,10); // '01234' str.slice(10,1); // '' |
var str = new String( '01234' ); str.substring(0,3); // '012' str.substring(1,3); // '12' str.substring(3,1); // '12' str.substring(3,-1); // '012' str.substring(3,0); // '012' str.substring(0); // '01234' str.substring(1); // '1234' str.substring(3); // '34' str.substring(1,1); // '' str.substring(-1); // '01234' str.substring(-3); // '01234' str.substring(-3,3); // '012' str.substring(-3,-1); // '' str.substring(-1,3); // '012' str.substring(10); // '' str.substring(0,10); // '01234' str.substring(10,1); // '1234' |
Stringオブジェクトから正規表現で文字列を検索し、一致した文字列を格納した配列を返します。取得が不要で一致するか調べるだけならばsearch()を用います。
String.match( regexp )String.match - JavaScript | MDN
一致した場合の戻り値はg属性の有無によって異なりますが、一致しなかった場合には、つねにnullが返されます。
引数に未定義値を与えると、空文字を要素に持つ配列が返されます。よって戻り値がnullではないことで、一致したとは判断できません。
var x;
'a'.match( x ); // [ "" ]
var str = new String( 'X abc123 bef456' ); var obj = str.match( /([a-z]+)([0-9]+)/ ); // obj[0] ... "abc123" // obj[1] ... "abc" // obj[2] ... "123" // obj.length ... 3 // obj.index ... 2 // obj.input ... "X abc123 bef456"
グローバルマッチ (g属性) では部分正規表現を取得できないため、その必要があるならばRegExp.exec()を使用します。
var str = new String( 'X abc123 bef456' ); var obj = str.match( /([a-z]+)([0-9]+)/g ); // obj[0] ... "abc123" // obj[1] ... "def456" // obj.length ... 2
このように、かっこによるグループ化が無視され、正規表現全体に一致した結果がそれぞれ配列に格納されて返されます。
Stringオブジェクトから正規表現に一致する文字列を検索し、その出現位置を返します。一致しない場合には-1が返されます。
String.search( regexp )String.search - JavaScript | MDN
一致するか調べるだけならばRegExp.test()を、検索に正規表現が不要ならばString.indexOf()を用います。
このメソッドはグローバルマッチ (g属性) を無視し、つねに最初のマッチング位置を返します。
引数の正規表現オブジェクトに未定義値を与えると、0が返されます。よって戻り値が-1ではないことで、一致したとは判断できません。Gecko 特有の注記 - String.prototype.search() - JavaScript | MDN
var x;
'a'.search( x ); // 0
一方でRegExp.test()では、同様の状況では例外が発生します。
var x;
x.test( 'a' ); // TypeError: x is undefined
検索パターンのregexpを文字列リテラルで指定した場合には、暗黙的にRegExpオブジェクトに変換されます。
'ab 12'.search( /[0-9]/ ); // 3 'ab 12'.search( '[0-9]' ); // 3
ただしバックスラッシュを記述する場合には、文字列リテラルではそれがエスケープシーケンスに用いられることに注意が必要です。
'ab 12'.search( /\d/ ); // 3 'ab 12'.search( '\d' ); // -1 'ab 12'.search( '\\d' ); // 3
空文字の正規表現を指定すると、最初の文字に一致したと見なされ0が返されます。ただし正規表現リテラルを空文字とすると、例外となります。
'abc'.search( new RegExp( '' ) ); // 0 'abc'.search( '' ); // 0 'abc'.search( // ); // SyntaxError: expected expression, got end of script
Stringオブジェクトから指定文字列に一致する文字列を検索し、その最初の出現位置を返します。一致しない場合には-1が返されます。
String.indexOf( searchValue [, fromIndex ] )String.indexOf - JavaScript | MDN
fromIndexは、Stringオブジェクトにおける検索を開始する位置です。
'abcabc'.indexOf( 'c' ); // 2 … 一致する文字列が2つあるが、その最初が返される 'abcabc'.indexOf( 'c', 2 ); // 2 … インデックスは0ベースのため、インデックス2は最初の'c' 'abcabc'.indexOf( 'c', 3 ); // 5 … 末尾の文字に一致したときは、String.lnegth-1の値となる 'abcabc'.indexOf( 'd' ); // -1 'abcabc'.indexOf( 'bc' ); // 1
indexOf()では、大文字と小文字は区別されます。
'a'.indexOf( 'a' ); // 0 'A'.indexOf( 'a' ); // -1
これを区別せずに検索するにはtoUpperCase()またはtoLowerCase()で、文字列を大文字/小文字のいずれかに統一してから判定します。
'a'.toLowerCase().indexOf( 'a' ); // 0 'A'.toLowerCase().indexOf( 'a' ); // 0
類似のメソッドにlastIndexOf()がありますが、こちらは最後の出現位置を返します。
'abcabc'.indexOf( 'c' ); // 2 'abcabc'.lastIndexOf( 'c' ); // 5
文字列にサロゲートペアの文字が含まれていると、見かけ上の位置とは一致しなくなります。
'あabc'.indexOf( 'a' ); // 1 '😀abc'.indexOf( 'a' ); // 2 'あabc'.charAt( 1 ); // "a" '😀abc'.charAt( 2 ); // "a" … 返された位置の文字を確認すると問題ない
Stringオブジェクトを、正規表現または文字列のパターンで指定文字列に置換し、置換した新しい文字列を返します。一致しない場合は、元の文字列がそのまま返されます。
String.replace( regexp, replacement )String.replace - JavaScript | MDN
第1引数のregexpには、RegExpオブジェクトまたは文字列を指定します。文字列を指定した場合はそれをテキストのパターン文字列として扱い、RegExpオブジェクトに変換することありません。この点はString.match()やString.search()とは異なります。
'ab.'.replace( '.', 'A' ); // "abA" 'ab.'.replace( /./, 'A' ); // "Ab."
regexpを文字列で指定したときには、最初に一致した1つの文字列しか置換されません。よって複数の文字列を置換するには、正規表現でg属性を指定します。
var str = new String( 'a a a' ); str.replace( 'a', 'A' ); // "A a a" str.replace( /a/, 'A' ); // "A a a" str.replace( /a/g, 'A' ); // "A A A"
第2引数のreplacementには、置換テキストを表す文字列または関数を指定します。
ドル記号 ($) が特別な意味を持ちます。
文字 | 置換文字列 |
---|---|
$n | n番目に一致したかっこで囲まれた部分文字列 (nは1~99) |
$& | 一致した部分文字列 |
$` | 一致した部分文字列の左側のテキスト |
$' | 一致した部分文字列の右側のテキスト |
$$ | 文字としてのドル記号 ($) |
var str = new String( 'aabbcc' ); str.replace( /(b+)(c+)/, '$2$1' ); // "aaccbb" str.replace( /b+(c+)/, '-$&-' ); // "aa-bbcc-" str.replace( /b/, '-$`-' ); // "aa-aa-bcc" str.replace( /b/, '-$\'-' ); // "aa-bcc-bcc"
第2引数に関数を指定した場合は、パターンに一致するごとにその関数が呼び出されます。そしてこの関数が返す文字列が、置換テキストとして使用されます。何も返さないと、文字列'undefined'に置換されます。
function replacer( str, p1, p2, offset, s ) { // 以下のように呼び出された場合、引数はそれぞれ次の値となります // str:"bbcc" // p1:"bb" // p2:"cc" // offset:2 // s:"aabbccdd" } new String( 'aabbccdd' ).replace( /(b+)(c+)/, replacer );
引数 | 説明 |
---|---|
str | パターンに一致した文字列 |
p1,p2, ... | パターン内のかっこで囲まれた部分正規表現に一致した文字列 ※グループ化のかっこの数だけ存在し、かっこがなければこの位置に次の引数であるoffsetが割り当てられる new String( 'abc' ).replace( /b/, function( str, offset, s ) { // str:"b" // offset:1 // s:"abc" } ); |
offset | 一致した位置を示す整数 |
s | 検索対象のstring自身 |
部分正規表現に一致した文字列を渡す引数 (p1,p2,...) は、0個以上存在します。つまりこの関数は、可変長の引数をとることに注意が必要です。
var text = 'abcde';
var newText = text.replace( /[bd]/g,
function( str )
{
return str.toUpperCase();
} );
// newTextは'aBcDe'となる
この方法はHTMLのタグを含む文字列で、タグ以外の文字列だけを置換するように、複雑な処理をする場合に有用です。またHTMLのマークアップ記号のエスケープなどの用法もあります。
Stringオブジェクトに、1つ以上の値を連結します。
concat( string2, string3[, ..., stringN] )String.concat - JavaScript | MDN
同様の処理は連結演算子 (+) で代用できるため、通常はそれを使用します。もし連結する値が配列に文字列として格納されているならば、それはArray.join()で連結できます。
ところでArray.concat()は配列の要素を結合し、より大きな配列とします。
Stringオブジェクトを区切り文字separatorで部分文字列に区切り、文字列の配列を返します。
split( [separator][, limit] );String.split - JavaScript | MDN
separatorを省略すると文字列は分割されず、要素を1つ持つ配列が返されます。第2引数のlimitは結果配列の要素数の上限であり、それを超える要素は結果から除外されます。たとえば、
new String( 'a-b-c-d' ).split( '-', 2)
とすると結果は[ "a", "b" ]と返され、そこには["c", "d"]はありません。なお区切り文字のseparatorには、文字列の他に正規表現も指定できます。
これメソッドとは逆に、配列を文字列に連結するのがjoin()です。
操作 | 結果 | ||
---|---|---|---|
サンプルコード | 説明 | 戻り値 | 説明 |
new String( '' ) .split( '' ) |
空文字を空文字で分割 | [] |
空配列 |
new String( '' ) .split( 'a' ) |
空文字を文字で分割 | [ "" ] |
空文字を要素に持つ配列 |
new String( 'abc' ) .split() |
文字列を分割しない | [ "abc" ] |
元の文字列を要素に持つ配列 |
new String( 'abc' ) .split( '' ) |
文字列を空文字で分割 | [ "a","b","c" ] |
文字の配列 |
new String( 'abc' ) .split( 'b' ) |
文字列を文字で分割 | [ "a","c" ] |
文字の配列 (区切り文字は含まれない) |
new String( 'abc' ) .split( 'z' ) |
文字列をそこに含まれない文字で分割 | [ "abc" ] |
元の文字列を要素に持つ配列 |
new String( 'a1b2c' ) .split( /[0-9]/ ) |
文字列を正規表現で分割 | [ "a","b","c" ] |
文字の配列 |
ECMAScript 2015 (6th Edition) 以降に対応した環境ならば、repeat()で処理できます。String.prototype.repeat() - JavaScript | MDN
専用の関数は用意されていないため、少し手間をかける必要があります。単純なのはループでくり返し文字列を連結する方法です。
var str = ''; for( var i = 0; i < 3; i++ ) str += 'ABC';
簡素に行いたいならば複数の要素を持つ配列を生成し、その要素を文字列で連結します。このとき配列の要素数は、くり返し数より1つ大きくする点に注意が必要です。
new Array( 4 ).join( 'ABC' ); // "ABCABCABC"
new Array( 0 ).join( 'A' ); // '' new Array( 1 ).join( 'A' ); // '' new Array( 2 ).join( 'A' ); // 'A' new Array( 3 ).join( 'A' ); // 'AA'
この方法を、配列の生成と連結で分けて考えると、
var a = new Array( 4 ); // このときaは、[ undefined, undefined, undefined, undefined ] a.join( 'ABC' ); // "ABCABCABC"が返される
となります。ちなみにPHPでは同様のことを、str_repeat()で行えます。
文字列の最大数はブラウザなどによって異なります。Javascript string size limit: 256 MB for me - is it the same for all browsers? - Stack Overflow
ブラウザ | 文字数の上限 | バイト数での換算 | 'a'.repeat(n) での例外メッセージ | (new Array(Math.pow(2,n)-m)).join('a') での例外メッセージ |
---|---|---|---|---|
Internet Explorer 11 | 2,147,483,646 (231-2) | 4,294,967,292 | (非対応) | メモリが不足しています。 |
Firefox 59 | 268,435,455 (228-1) | 536,870,910 | RangeError: repeat count must be less than infinity and not overflow maximum string size | InternalError: allocation size overflow |
Chrome 65 | 1,073,741,799 (230-25) | 2,147,483,598 | RangeError: Invalid string length | RangeError: Invalid string length |
組み込みのメソッドで変換できます。
指定位置の文字の、Unicodeコードポイント (UTF-16) を取得します。
var codepoint = string.charCodeAt( index )charCodeAt - JavaScript | MDN
戻り値は0~65,535 (0xFFFF) の範囲で、このうち127まではASCII文字に対応しています。
new String( 'AB' ).charCodeAt( 0 ); // 65 new String( 'AB' ).charCodeAt( 1 ); // 66 new String( 'AB' ).charCodeAt( 2 ); // NaN new String( 'あ' ).charCodeAt( 0 ); // 12354 (0x3042)
Unicodeの範囲は0~1,114,111 (0x10FFFF) のため、charCodeAt()ではサロゲートペアのコードを上位と下位に分けて取得します。
// '𠀋' 0x2000B [UTF-32] '𠀋'.charCodeAt( 0 ); // 55360 (0xDB40) '𠀋'.charCodeAt( 1 ); // 56331 (0xDC0B)
codePointAt()がサポートされるならば、このような場合にも処理を分けることはありません。
'𠀋'.codePointAt( 0 ); // 131083 (0x2000B)
String.prototype.codePointAt() - JavaScript | MDN
0~127まではASCII文字に対応するため、
'A'.charCodeAt( 0 ); // 65
のようにすれば、指定文字のASCIIコードを取得できます。なお同様のことをPHPでは、ord()で行えます。
Unicodeコードポイントに対応する文字を取得します。
String.fromCharCode( num1 [, ...[, numN ] ] )String.fromCharCode() - JavaScript | MDN
String.fromCharCode( 65 ); // 'A' String.fromCharCode( 0x41 ); // 'A' String.fromCharCode( 12354 ); // 'あ' String.fromCharCode( 0x3042 ); // 'あ'
文字列リテラルで記述するならば、'\u3042'
はString.fromCharCode( 0x3042 )
と等しい文字を返します。複数の引数を渡した場合には、個々の引数が変換された結果が連結されて返されます。
String.fromCharCode( 65, 66 ); // 'AB'
fromCharCode()は16ビットの数値しか受け入れないため、サロゲートペアの文字は上位と下位に分けて指定します。
String.fromCharCode( 55360 ); // '��' String.fromCharCode( 56331 ); // '��' String.fromCharCode( 55360, 56331 ); // '𠀋' String.fromCharCode( 55360 ) + String.fromCharCode( 56331 ); // '𠀋'
UTF-8へエンコードできるメソッドは用意されていないため、まずcodePointAt()でUnicodeのコードポイントを取得します。そしてそれをUTF-8のエンコーディングに従い変換します。
function Encode( text ) { var codePoint = text.codePointAt( 0 ); // ここでは1文字目だけを対象とする if( 0xd800 <= codePoint && codePoint <= 0xdfff ) return null; // サロゲートペアは対象外 var bytes = []; if( codePoint < 0x80 ) { bytes = [ codePoint ]; } else if( codePoint < 0x800 ) { bytes = [ ( codePoint & 0b0000011111000000 ) >> 6 | 0b11000000, ( codePoint & 0b0000000000111111 ) | 0b10000000 ]; } else if( codePoint < 0x10000 ) { bytes = [ ( codePoint & 0b1111000000000000 ) >> 12 | 0b11100000, ( codePoint & 0b0000111111000000 ) >> 6 | 0b10000000, ( codePoint & 0b0000000000111111 ) | 0b10000000 ]; } else if( codePoint < 0x110000 ) { bytes = [ ( codePoint & 0b000111000000000000000000 ) >> 18 | 0b11110000, ( codePoint & 0b000000111111000000000000 ) >> 12 | 0b10000000, ( codePoint & 0b000000000000111111000000 ) >> 6 | 0b10000000, ( codePoint & 0b000000000000000000111111 ) | 0b10000000 ]; } var hex = []; for( var i = 0; i < bytes.length; i++ ) { hex.push( bytes[ i ].toString( 16 ) ); } return hex.join( '' ); // 引数textが'あ'ならば、'e38182'が返される }
なおTextEncoderがサポートされる環境ならば、それでもエンコードできます。
var textEncoder = new TextEncoder();
var array = textEncoder.encode( 'あ' ); // "227,129,130" (0xE3,0x81,0x82)
エンコードの逆です。
function Decode( hexStr )
{
var num = parseInt( hexStr, 16 );
var codePoint;
if( num <= 0xff )
{
codePoint = num;
}
else if( num <= 0xffff )
{
codePoint = num & 0b111111
| ( ( num >> 2 ) & 0b11111000000 );
}
else if( num <= 0xffffff )
{
codePoint = num & 0b111111
| ( ( num >> 2 ) & 0b0000111111000000 )
| ( ( num >> 4 ) & 0b1111000000000000 );
}
else if( num <= 0xffffffff )
{
codePoint = num & 0b111111
| ( ( num >> 2 ) & 0b000000000111111000000 )
| ( ( num >> 4 ) & 0b000111111000000000000 )
| ( ( num >> 6 ) & 0b111000000000000000000 );
}
return String.fromCodePoint( codePoint ); // 引数hexStrが'e38182'ならば、'あ'が返される
}
TextDecoderがサポートされる環境では、次のように記述できます。
var textDecoder = new TextDecoder( 'utf-8', { fatal: true } ); var buffer = new Uint8Array( [ 0xE3, 0x81, 0x82 ] ); try { var text = textDecoder.decode( buffer ); // 'あ' } catch( e ) { if( e.name == 'TypeError' ) // 無効なコード }
function Decode( text ) { var codes = []; var match; var pattern = /\\x([0-9a-f][0-9a-f])/gi; while( match = pattern.exec( text ) ) { var code = parseInt( match[ 1 ], 16 ); codes.push( code ); } var binary = new Uint8Array( codes ).buffer; var blob = new Blob( [ binary ] ); var reader = new FileReader(); reader.onloadend = function() { console.log( reader.result ); } reader.readAsText( blob, 'shift_jis' ); }
TextDecoderならば、これは次のように記述できます。
var textDecoder = new TextDecoder( 'shift-jis' );
var buffer = new Uint8Array( [ 0x82, 0xA0 ] );
var text = textDecoder.decode( buffer ); // 'あ'
文字列をURLエンコード/デコードする関数が、グローバル関数として定義されています。
URLに使用できない文字をエスケープする処理はURL encodingと呼ばれることが多いですが、JavaScriptの関数名としてはencodeURIです。
encodeURI( str )encodeURI() - JavaScript | MDN
encodeURIComponent( str )encodeURIComponent() - JavaScript | MDN
このencodeURI()とencodeURIComponent()では、エンコードの対象とする文字が異なります。この違いはdecodeURI()でも同様です。
文字種 | encodeURI decodeURI |
encodeURIComponent decodeURIComponent |
---|---|---|
英数字 | 変換されない | |
予約文字1 (- _ . ! ~ * ' ( ) ) |
||
予約文字2 (; , / ? : @ & = + $ ) |
変換されない | 変換される |
番号記号 (# ) |
||
上記以外 | 変換される |
encodeURI(';'); // ';' encodeURIComponent(';'); // '%3B' encodeURI('あ'); // '%E3%81%82' encodeURIComponent('あ'); // '%E3%81%82'
ところで、ここで「あ」をエンコードした結果である「%E3%81%82」は、UTF-8での文字コードです。
var encodedData = window.btoa( stringToEncode )WindowBase64.btoa() - Web APIs | MDN
window.btoa('A'); // "QQ=="
この関数はバイナリデータを対象としており、Unicode文字列を直接扱えません。window.btoa('あ')
のようにUnicode文字を与えると、例外が発生します。The "Unicode Problem" - Base64 encoding and decoding - Web APIs | MDN
よって、先にUTF-8をエンコード/デコードする方法で処理した上で渡します。
window.btoa( unescape( encodeURIComponent( 'あ' ) ) ); // "44GC"
var decodedData = window.atob( encodedData )WindowBase64.atob() - Web APIs | MDN
window.atob( 'QQ==' ); // "A"
デコードもエンコード同様に、Unicode文字列を直接扱えません。
window.atob( '44GC' ); // "ã"
よって次のようにします。
decodeURIComponent( escape( window.atob( '44GC' ) ) ); // "あ"
Unicodeがサポートされることで、類似の文字が多数存在します。これらは一見するだけでは区別できないため、注意が必要です。
これらは異なる文字のため、比較演算では偽と見なされます。
' ' == ' '; // true ' ' == '\x20'; // true ' ' == '\xA0'; // false '\x20' == '\xA0'; // false '\x20' == '\u0020'; // true
このことは次のような場合に問題となります。
alert( a ); // "1 2" alert( b ); // "1 2" // これらの2つの変数は外見上は同じく表示されますが、比較すると一致しません。 alert( a == b ); // false // このような場合にはエスケープすると違いを確認できます。 alert( escape( a ) ); // "1%202" alert( escape( b ) ); // "1%A02"
この空白文字の問題は、正規表現の/\s/
を用いることで対応できます。