[JavaScript] Unicode を含む文字列を一部切り出すなら unicode-substring を使うべき

JavaScript や Node.js で Unicode を含む文字列を一部切り出したい場合 substring ではなく unicode-substring を使うべきという事例とサンプルコードをご紹介します。

JavaScript

背景 substring + encodeURI = URIError: malformed URI sequence

String.prototype.substring() で一部を切り出した文字列を encodeURI メソッドの引数に渡すと、Unicode 上位サロゲートのみが残った文字列だった場合 URIError: malformed URI sequence エラーが発生します。

substring の代わりに unicode-substring を使おう

同僚のシニアエンジニアから「Unicode の仕様は複雑なので String.prototype.substring() で扱わない方が良い」というアドバイスを頂きました。

参考: FAQ – UTF-8, UTF-16, UTF-32 & BOM

unicode-substring

String.prototype.substring() の代わりに unicode-substring をオススメされたので、早速使ってみました。

substring, unicode-substring の Node.js repl 実行例

const unicodeSubstring = require('unicode-substring');
const string = "💥💥Emoji💥💥";

// str.substring(indexStart[, indexEnd])

console.log(string.substring(0, 3)); // 💥�


// unicodeSubstring(string, start, end)

console.log(unicodeSubstring(string, 0, 3)); // 💥💥E

substring vs unicode-substring サンプルコード

Compare String.prototype.substring() vs unicode-substring (sample codes) · Pull Request #5 · codenote-net/expressjs-sandbox

上記の pull request のコードにて http://localhost:3000/unicode からフォーム送信した結果が以下のとおりです。

GET /unicode
unicode-substring input form

POST /unicode/substring
unicode-substring response json

実行結果 – Response JSON
unicode-substring – npm

{
    body: {
        substring: "💥💥Emoji💥💥",
        unicodeSubstring: "💥💥Emoji💥💥",
        start: "0",
        end: "3"
    },
    formatted: {
        substring: "💥�",
        unicodeSubstring: "💥💥E"
    }
}

Code Reading) unicode-substring

unicode-substring/index.js はコード量が少ないので、もし時間があれば Code Reading してみると Unicode の理解が深まると思います。

以上、JavaScript や Node.js で Unicode を含む文字列には substring ではなく unicode-substring を使うべきという学びを得た、現場からお送りしました。