NodeJS を使用してフロントエンド ツールを作成する場合、最も一般的に使用されるのはテキスト ファイルであるため、ファイル エンコーディングの問題も関係します。一般的に使用されるテキスト エンコーディングは UTF8 と GBK で、UTF8 ファイルには BOM が含まれる場合もあります。異なるエンコーディングのテキスト ファイルを読み取る場合は、ファイルの内容を通常に処理する前に、JS で使用される UTF8 エンコード文字列に変換する必要があります。
BOM の削除
BOM は、Unicode エンコードを使用してテキスト ファイルをマークするために使用されます。BOM 自体は、テキスト ファイルのヘッダーにある Unicode 文字 (「uFEFF」) です。さまざまな Unicode エンコードでは、BOM 文字に対応するバイナリ バイトは次のとおりです:
Bytes Encoding ---------------------------- FE FF UTF16BE FF FE UTF16LE EF BB BF UTF8
したがって、テキスト ファイルの最初の数バイトが何に等しいかに基づいて、ファイルに BOM が含まれているかどうか、およびどの Unicode エンコードを使用するかを決定できます。ただし、BOM 文字はファイルのエンコーディングをマークする役割を果たしますが、テキスト ファイルを読み取るときに BOM が削除されない場合、特定の使用シナリオで問題が発生します。たとえば、複数の JS ファイルを 1 つのファイルにマージした後、ファイルに BOM 文字が含まれていると、ブラウザーの JS 構文エラーが発生します。したがって、NodeJS を使用してテキスト ファイルを読み取る場合は、通常、BOM を削除する必要があります。たとえば、次のコードは、UTF8 BOM を識別して削除する機能を実装します。
function readText(pathname) { var bin = fs.readFileSync(pathname); if (bin[0] === 0xEF && bin[1] === 0xBB && bin[2] === 0xBF) { bin = bin.slice(3); } return bin.toString('utf-8'); }
GBK から UTF8 へ
NodeJS は、テキスト ファイルを読み取るとき、またはバッファーを文字列に変換するときにテキスト エンコーディングの指定をサポートしていますが、残念ながら、GBK エンコーディングは NodeJS 自体のサポートの範囲内ではありません。したがって、通常はサードパーティのパッケージ iconv-lite を使用してエンコードを変換します。 NPM を使用してパッケージをダウンロードした後、次のように GBK テキスト ファイルを読み取る関数を作成できます。
var iconv = require('iconv-lite'); function readGBKText(pathname) { var bin = fs.readFileSync(pathname); return iconv.decode(bin, 'gbk'); }
シングルバイトエンコーディング
場合によっては、読み取る必要があるファイルがどのエンコーディングを使用しているかを予測できないため、正しいエンコーディングを指定できません。たとえば、処理する必要がある CSS ファイルの一部は GBK でエンコードされ、一部は UTF8 でエンコードされます。ファイルのバイト内容に基づいてテキストのエンコーディングをある程度推測することは可能ですが、ここで紹介するのはある程度限定的ではありますが、より簡単な手法です。
まず、テキスト ファイルに Hello World などの英語の文字のみが含まれている場合は、GBK エンコードまたは UTF8 エンコードを使用してファイルを読み取ることに問題はないことがわかっています。これは、これらのエンコーディングでは、ASCII0 ~ 128 の範囲の文字が同じシングルバイト エンコーディングを使用するためです。
一方、テキストファイル内に中国語などの文字が含まれていても、コメントや文字列を除くJSコードなど、処理する必要がある文字がASCII0~128の範囲のみであれば、ファイルを読み取る際のエンコーディングは一律に 1 バイトです。ファイルの実際のエンコーディングが GBK か UTF8 かを気にする必要はありません。次の例は、このアプローチを示しています。
1. GBK エンコード ソース ファイルの内容:
var foo = '中文';
2. 対応するバイト:
76 61 72 20 66 6F 6F 20 3D 20 27 D6 D0 CE C4 27 3B
3. シングルバイトエンコードを使用して読み取った後に取得されるコンテンツ:
var foo = '{乱码}{乱码}{乱码}{乱码}';
4. 置換内容:
var bar = '{乱码}{乱码}{乱码}{乱码}';
5. シングルバイトエンコーディングを使用して保存した後の対応するバイト:
76 61 72 20 62 61 72 20 3D 20 27 D6 D0 CE C4 27 3B
6. GBK エンコードを使用してコンテンツを読み取り、取得します。
var bar = '中文';
ここでのコツは、0xEF より大きい 1 バイトが 1 バイト エンコーディングでどのような文字化けに解析されたとしても、これらの文字化けが同じ 1 バイト エンコーディングで保存されると、その後ろにある対応するバイトは変更されないということです。
NodeJS には、このメソッドの実装に使用できるバイナリ エンコーディングが付属しています。そのため、次の例では、このエンコーディングを使用して、上記の例に対応するコードを記述する方法を示します。
function replace(pathname) { var str = fs.readFileSync(pathname, 'binary'); str = str.replace('foo', 'bar'); fs.writeFileSync(pathname, str, 'binary'); }