複数ファイルの文字コードを判定して一覧出力するサクラエディタのマクロ

# 概要

フォルダ内に大量のテキストファイルがあり、それらの文字コードを一括で調べる必要があったので、ファイルの文字コードを判定して一覧として出力するサクラエディタのマクロを作ってみた。

# マクロのコード

```js:sakuramacro-check-charcode.js

var TARGET_FOLDER = "C:\\Test";
var FILE_PATTERN = /\.txt$/;

main();

function main() {
    var shell = new ActiveXObject("WScript.Shell");
    var resultFileFolder = shell.ExpandEnvironmentStrings("%TEMP%");
    var resultFileName = "Result_" + formatYyyymmddhhmmss(new Date) + ".txt";
    var fso = new ActiveXObject("Scripting.FileSystemObject");
    var resultTextStream = fso.GetFolder(resultFileFolder).CreateTextFile(resultFileName);
    for (var filePaths = new Enumerator(getFilePathsRecursive(fso.GetFolder(TARGET_FOLDER), FILE_PATTERN)) ; !filePaths.atEnd() ; filePaths.moveNext()) {
        resultTextStream.WriteLine(getFileCharCode(filePaths.item()));
    }    
    resultTextStream.Close();
    Editor.FileOpen(resultFileFolder + "\\" + resultFileName);
}

function formatYyyymmddhhmmss(date) {
    var ret = "";
    ret += date.getFullYear();
    ret += ("0" + (date.getMonth() + 1)).slice(-2);
    ret += ("0" + date.getDate()).slice(-2);
    ret += ("0" + date.getHours()).slice(-2);
    ret += ("0" + date.getMinutes()).slice(-2);
    ret += ("0" + date.getSeconds()).slice(-2);
    return ret;
}

function getFilePathsRecursive(folder, pattern) {
    var array = [];
    for (var files = new Enumerator(folder.Files) ; !files.atEnd() ; files.moveNext()) {
        var file = files.item();
        if (pattern.test(file.Name)) {
            array.push(folder.Path + "\\" + file.Name);
        }
    }
    for (var subFolders = new Enumerator(folder.SubFolders) ; !subFolders.atEnd() ; subFolders.moveNext()) {
        var newArray = array.concat(getFilePathsRecursive(subFolders.item(), pattern));
        array = newArray;
    }
    return array;
}

function getFileCharCode(filePath) {
    var charCode = "";
    var stream = new ActiveXObject("ADODB.Stream");
    stream.Open();
    stream.Type = 1;
    stream.LoadFromFile(filePath);
    if (stream.Size > 1) {
        stream.Position = 0;
        switch (bytes2hex(stream.Read(2))) {
            case "feff":
                charCode = "UTF-16 BOM有(BE)";
                break;
            case "fffe":
                charCode = "UTF-16 BOM有(LE)";
                break;
        }
    }
    if (charCode === "" && stream.Size > 2) {
        stream.Position = 0;
        switch (bytes2hex(stream.Read(3))) {
            case "2b2f76":
                charCode = "UTF-7 BOM有";
                break;
            case "efbbbf":
                charCode = "UTF-8 BOM有";
                break;
        }
    }
    stream.Close();
    if (charCode === "") {
        Editor.FileOpen(filePath);
        Editor.Sleep(20);
        switch (Editor.GetCharCode()) {
            case 0:
                charCode = "SJIS";
                break;
            case 1:
                charCode = "JIS";
                break;
            case 2:
                charCode = "EUC";
                break;
            case 3:
                charCode = "UTF-16 BOM無";
                break;
            case 4:
                charCode = "UTF-8 BOM無";
                break;
            case 5:
                charCode = "UTF-7 BOM無";
                break;
            case 6:
                charCode = "UTF-16BE";
                break;
            case 7:
                charCode = "CESU-8";
                break;
            case 8:
                charCode = "Latin1";
                break;
            case 90:
                charCode = "CP_ACP";
                break;
            case 91:
                charCode = "CP_OEM";
                break;
            default:
                charCode = "Unknown";
                break;
        }
        Editor.FileClose();
    }
    return filePath + "\t" + charCode;
}

function bytes2hex(bytes) {
    var doc = new ActiveXObject("Msxml2.DOMDocument");
    var element = doc.createElement("hex");
    element.dataType = "bin.hex";
    element.nodeTypedValue = bytes;
    var hex = element.text;
    return hex;
}
```

# 使い方

1. 上記のコードをコピーしてテキストに貼り付け、拡張子「.js」で保存する。
 - 「TARGET_FOLDER」と「FILE_PATTERN」は適宜書き換えること。
2. サクラエディタを起動する。
 - サクラエディタのウィンドウが複数開かれているとうまく動作しないので、1つ以外はすべて閉じておくこと。
3. メニューの「ツール」→「名前を指定してマクロ実行」をクリックする。
![picture01.png](https://qiita-image-store.s3.amazonaws.com/0/135864/7b9c306b-e921-ed03-faa7-b7cf076b14c5.png)
4. 1で保存したマクロのファイルを選択し、「開く」をクリックする。
5. すべての対象ファイルの文字コード判定が終わると、一覧が表示される。
![picture02_3.png](https://qiita-image-store.s3.amazonaws.com/0/135864/a59ccd1e-1df2-1636-3042-4946611771f5.png)