JavaScript や Node.js で Unicode を含む文字列を一部切り出したい場合 substring ではなく unicode-substring を使うべきという事例とサンプルコードをご紹介します。
背景 substring + encodeURI = URIError: malformed URI sequence
String.prototype.substring() で一部を切り出した文字列を encodeURI メソッドの引数に渡すと、Unicode 上位サロゲートのみが残った文字列だった場合 URIError: malformed URI sequence エラーが発生します。
- String.prototype.substring() - JavaScript | MDN
- URIError: malformed URI sequence - JavaScript | MDN
- Unicode - Wikipedia
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 サンプルコード
上記の pull request のコードにて http://localhost:3000/unicode からフォーム送信した結果が以下のとおりです。
GET /unicode

POST /unicode/substring

実行結果 - 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 を使うべきという学びを得た、現場からお送りしました。