現象
Node.jsで取得したフォルダ名と文字列リテラルが同じ文字(っぽい)のに一致しない。
ただし濁点付きの文字に限る。
- 確認した環境
- macOS Sierra v10.12.6
- node v8.2.1
再現手順
こんな感じでフォルダがあったとする。
$ ll /data
total 0
-rw-r--r-- 1 mimizq staff 0 1 2 00:06 せ
-rw-r--r-- 1 mimizq staff 0 1 2 00:06 ぜ
フォルダ一覧を取得する。
const fs = require('fs');
const chars = fs.readdirSync('/data');
// [せ, ぜ]
濁点付きの文字だけ一致しない。
let countA = 0;
let countB = 0;
for(let c of chars) {
if(c === 'せ') countA++;
if(c === 'ぜ') countB++;
}
console.log(countA); // 1
console.log(countB); // 0
なぜ一致しないのか
文字コードが違うから。
for(let c of chars) {
console.log(c.charCodeAt(0));
}
// 12379
// 12379
// フォルダ名の「ぜ」は、 12379, 12441 となっており、濁点入りで実質2文字扱い。
// 一方、リテラルの「ぜ」は、12380 で1文字扱い。なので当然一致しない。
理由
macOSのファイルシステムの問題らしい。
こちらの方が詳しく書いてくださっているのでリンクしておきます。
https://qiita.com/knaka/items/48e1799b56d520af6a09
結論
こうすればいい。
const chars = fs.readdirSync('/data')
.map(c => {
return c.normalize('NFC'); // NFCで正規化
});
let countA = 0;
let countB = 0;
for(let c of chars) {
if(c === 'せ') countA++;
if(c === 'ぜ') countB++;
}
console.log(countA); // 1
console.log(countB); // 1 <- 一致した
for(let c of chars) {
console.log(c.charCodeAt(0));
}
// 12379
// 12380 <- 1文字扱いされている
だからテキストエディタでソートしたときの挙動が意図していたものと違ったのかと納得。
macを使い始めて数ヶ月経ちますが、操作はそこそこ慣れてもOSの仕様的なところは全然知らないので結構困ります。
総合的な開発効率は正直Windowsのほうが上だったような。
最近のWindowsはWSLでBash使えるし。
慣れの問題でしょうか。
英語環境だとmac良いのかもしれないけど日本語環境だとちょっと使いづらいかも。
小洒落たポスターとかスライド作るにはいいんだけど。