Mukai Systems

IEのための文字列から文字の配列取得処理

javascriptで文字列から文字の配列を得ようとするときにString.prototype.split()を使用するのは、よくある間違いのようである。

Note: This is not unicode compliant.
    "I💖U".split('')
results in the 4 character array ["I", "�", "�", "u"] which can lead to dangerous bugs.
See answers below for safe alternatives.

-- How to get character array from a string?

これは、splitがサロゲートペアを考慮することなしにUTF-16のコードユニット単位に分解するからである。

参照先にもあるように、ES2015をサポートしているブラウザならばspread syntaxで済む。

const a = [...'I💖U'];

そうでない場合、少し調べて見つからなかったのでプログラムを書いてみた。

function eachChar(str, fn) {
    var i = 0;
    while (i < str.length) {
        var code = str.charCodeAt(i++);
        if ((code & 0xF800) != 0xD800) fn(String.fromCharCode(code))
        else {
            var hi = code;
            var low = str.charCodeAt(i++);
            fn(String.fromCharCode(hi, low));
        }
    }
}

eachCharは、文字列strを構成する文字ごとにコールバック関数fnを呼び出す高階関数である。String.prototype.charCodeAt()で指定した位置のコードユニットを取得できるので、参照したコードユニットがハイサロゲートだった場合は後続するローサロゲートをサロゲートペアとして扱っている。また、String.lengthがUTF-16のコードユニット数を返すことにも注意が必要である。

各文字に対して一度処理するだけならばこれで充分である。

eachChar('I💖U', console.log);

文字の配列にしたい場合は追加で、以下のようなコードを書けばよい。

function charArray(str) {
    var ret = [];
    eachChar(str, function(ch) {
        ret.push(ch);
    });
    return ret;
}

const a = charArray('I💖U');

おしまい。