Node.jsでCSVファイルの文字コードやカラムを編集して保存する

Node.jsを使って何かしらのcsvファイルをUTF-8に変換、さらにそのCSVファイルの指定した列を削除して、新しいファイルとして書き出す方法をご紹介します。


# 必要なモジュールのインストール
```bash
npm i csv --save
npm i iconv-lite --save
npm i encoding-japanese --save
```

csvは文字列をCSVファイルに変換するために、iconv-liteはファイルの文字コードを変換するために、encoding-japaneseはファイルの文字コードを判別するために使います。

# 今回行う処理

今回は入力されたSHIFT-JISのファイルをUTF-8に変換。さらには不必要な列を削除すると共に、1行目の項目名の変更などを行います。

具体例を出すと、下記のような形です。項目名を日本語➡️英語に編集。さらには不要なパスワード、住所・郵便番号の項目は削除、そして複数あるメールアドレスに関しては（メール２が配列になっているデータもあります）、それぞれ一行ずつにして表します。

想定としては、顧客リストなどの個人情報の入ったデータを、登録に必要な情報のみに変換して、何かしらの用途に用いるなどが考えられます。

```
ID,名前,メール1,パスワード,メール2,郵便番号,住所
1,Bob,test@bob.com,xxxxxx,test2@bob.com,xxx-xxxx,xxxxxxxx
2,Alice,test@alice.com,xxxxxx,test2@alice.com,xxx-xxxx,xxxxxxxx
3,Naomi,test@naomi.com,xxxxxx,test2@naomi.com,xxx-xxxx,xxxxxxxx
4,Key,test@key.com,xxxxxx,"test2@key.com,test3@key.com",xxx-xxxx,xxxxxxxx
5,Annna,test@annna.com,xxxxxx,"test2@annna.com,test3@annna.com,test4@annna.com",xxx-xxxx,xxxxxxxx
                
                ↓
      
id,name,email
1,Bob,test@bob.com
1,Bob,test2@bob.com
2,Alice,test@alice.com
2,Alice,test2@alice.com
3,Naomi,test@naomi.com
3,Naomi,test2@naomi.com
4,Key,test@key.com
4,Key,test2@key.com
4,Key,test3@key.com
5,Annna,test@annna.com
5,Annna,test2@annna.com
5,Annna,test3@annna.com
5,Annna,test4@annna.com


```



# 実際の処理
では実際の処理を紹介します。

```javascript
const fs = require('fs');
const csv = require('csv');
const iconv = require('iconv-lite');
const encoding = require('encoding-japanese');
const parser = csv.parse((error, data) => {

    let newData = [];

    //ループしながら１行ずつ処理
    data.forEach((element, index, array) => {
        if(index == 0){
            let row = [];
            row.push('id');
            row.push('name');
            row.push('email');
            newData.push(row);
            return newData;
        }else{
            let row = [];
            createNewRow(element,row,element[2],newData);
            if(element[4].indexOf('@') != -1){
                if(element[4].indexOf(',') != -1){
                    var arr = element[4].split(',');
                    for(i=0; i < arr.length; i++){
                        let row = [];
                        createNewRow(element,row,arr[i],newData);
                    }
                }else{
                    let row = [];
                    createNewRow(element,row,element[4],newData);
                }
            }
        }
    })
    //write
    csv.stringify(newData,(error,output)=>{
        fs.writeFile('編集・変換後のファイル名.csv',output,(error)=>{
            console.log('処理データをCSV出力しました。');
        })
    })
})

var buf = fs.readFileSync('ファイル名.csv');
if(encoding.detect(buf) == 'SJIS'){

    fs.readFile('ファイル名.csv', function(err, data){
        if (err) throw err;
        var buf    = new Buffer.from(data, 'binary');  //バイナリバッファを一時的に作成する
        var retStr = iconv.decode(buf, "Shift_JIS"); //作成したバッファを使い、iconv-liteでShift-jisからutf8に変換
        fs.writeFile('変換後のファイル名.csv',retStr,(error)=>{
            console.log('処理データをCSV出力しました。');
        });
        fs.createReadStream('変換後のファイル名.csv').pipe(parser);
    });
}else if(encoding.detect(buf) == 'ASCII'){
    fs.createReadStream('ファイル名.csv').pipe(parser);
}else{
    console.log('この形式のファイルでは文字コードを変換できません。SHIFT-JISかUTF8のみ対応しています');
}

function createNewRow(element,row, email, newData){
    row.push(element[0]);
    row.push(element[1]);
    row.push(email);

    newData.push(row);
    return newData;
}

```

細かく分けて説明していきます。もともとShift-jisだったcsvファイルの文字コードをUTF8に変更します。

```javascript

var buf = fs.readFileSync('ファイル名.csv');
if(encoding.detect(buf) == 'SJIS'){

    fs.readFile('ファイル名.csv', function(err, data){
        if (err) throw err;
        var buf    = new Buffer.from(data, 'binary'); 
        var retStr = iconv.decode(buf, "Shift_JIS"); //作成したバッファを使い、iconv-liteでShift-jisからutf8に変換
        fs.writeFile('変換後のファイル名.csv',retStr,(error)=>{
            console.log('処理データをCSV出力しました。');
        });
        fs.createReadStream('変換後のファイル名.csv').pipe(parser);
    });
}else if(encoding.detect(buf) == 'ASCII'){
    fs.createReadStream('ファイル名.csv').pipe(parser);
}else{
    console.log('この形式のファイルでは文字コードを変換できません。SHIFT-JISかUTF8のみ対応しています');
}

```

次は実際に編集をする処理です。


```javascript


const parser = csv.parse((error, data) => {

    let newData = [];

    data.forEach((element, index, array) => {
        if(index == 0){
            let row = [];
            row.push('id');
            row.push('name');
            row.push('email');
            newData.push(row);
            return newData;
        }else{
            let row = [];
            createNewRow(element,row,element[2],newData);
            if(element[4].indexOf('@') != -1){
                if(element[4].indexOf(',') != -1){
                    var arr = element[4].split(',');
                    for(i=0; i < arr.length; i++){
                        let row = [];
                        createNewRow(element,row,arr[i],newData);
                    }
                }else{
                    let row = [];
                    createNewRow(element,row,element[4],newData);
                }
            }
        }
    })
    
    csv.stringify(newData,(error,output)=>{
        fs.writeFile('編集・変換後のファイル名.csv',output,(error)=>{
            console.log('出力成功');
        })
    })
})

function createNewRow(element,row, email, newData){
    row.push(element[0]);
    row.push(element[1]);
    row.push(email);

    newData.push(row);
    return newData;
}

```


csvモジュールの機能を使って、csvファイルをparseします。元のcsvファイルを一行ずつ処理していきます。一行目は大きく描き変えるために、新しい要素を直接書き込みます。二行目以降に関しては、必要な要素のみを抽出して処理します。

そしてメール2の項目の要素を持っている行に関しては、それをEmailに当てはめます。メール２項目を複数持っている物に関しては、そのようがカンマを持っていることで判別して、カンマで分割することで、配列要素にしそれを１つずつ行に入れていきます。

そして、それらのデータが入ったnewDataをfs.writeFileでcsvファイルとして書き出します。


以上になります。

# 参考記事
https://solutionware.jp/blog/2016/09/29/node-js%E3%81%A7csv%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E6%93%8D%E4%BD%9C/