Quantcast
Channel: 配列タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 841

【駆逐してやる...】JavaScriptでExcelブックを配列化【1ファイル残らず!】

$
0
0

久々の業務で役立つ(かも?)シリーズです。

「受け取ったデータが.xlsxだった...」
「社内システムが.xlsxしか吐き出してくれない...」
.xlsxをこねくり回すと全身に拒絶反応が...

そのような絶望とも今日でおさらば!

js-xlsx

.xlsx以外にも.xls.odsなど、大抵の表計算ファイルをJavaScriptから扱えます。

もちろんShift-JISにも対応しており、なんとNode/Browserどちらでも使えます。

まさに救世主!

導入

Browser
<script src="https://cdn.jsdelivr.net/npm/xlsx@latest/dist/xlsx.full.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/xlsx@latest/dist/cpexcel.js"></script>

グローバル領域にXLSXオブジェクトが展開されます。
cpexcel.jsは追加の文字コードセットで、これが無いとShift-JISを認識できません。

Node
const XLSX = require("xlsx");

こちらは単純明快。
文字コードセットは全て内包されているので問題ありません。

コード

JavaScript
function parseSheet(blob){
    return new Promise((res, rej)=>{
        const fr = new FileReader();
        fr.addEventListener("load", () => res(fr.result));
        fr.addEventListener("error", () => rej(fr.error));
        fr.readAsArrayBuffer(blob);
    }).then((bin)=>{
        const book = XLSX.read(bin, {
            type: "array",
            codepage: 932
        });

        const sheets = book.SheetNames.map((name)=>{
            const sheet = XLSX.utils.sheet_to_csv(book.Sheets[name], {
                FS: "\u001F"
            }).split("\n").map((row)=>{
                return row.split("\u001F").map((field)=>{
                    if(/^$/.test(field)){
                        return null;
                    }
                    else if(/^true$/i.test(field)){
                        return true;
                    }
                    else if(/^false$/i.test(field)){
                        return false;
                    }
                    else if(/^((|-)((\d{1,3},){0,}\d{3}|\d+)|0(X|x)[0-9a-fA-F]+|0(B|b)[0-1]+)$/.test(field)){
                        const s = field.replace(/,/g, "");
                        const n = Number(s);
                        return Number.isSafeInteger(n) ? n : BigInt(s);
                    }
                    else{
                        return String(field);
                    }
                });
            });

            return {
                [name]: sheet
            };
        });

        return Object.assign(...sheets);
    });
}

各シートを一旦CSVにしてから、各フィールドの型判定を行い二次元配列化しています。

空白セルはnullとなります。
Numberは、桁区切りでカンマが入っていたり16進や2進の表記でも問題ありません。
値が巨大な場合はBigIntとなります。
それ以外の文字列はStringです。

出力されるオブジェクトは、下記のようなデータ構造です。

DataStructure
{
    "シート名": [/*行番号*/][/*列番号*/],
    ...
}

使う

HowToUse.js
const file; // 任意の表計算ファイル

const parsed = parseSheet(file);

console.log(parsed["シート1"][0][0]); // シート1のA1セルに相当

行/列の番号が0スタートなところさえ気を付ければ、特に難しい操作はありません。

これで正規表現での総当りも、条件付きSUMも、フォームへの自動入力も思いのまま!

おわりに

Excelのない朝は
今よりずっと素晴らしくて
すべての歯車が噛み合った
きっとそんな世界だ


Viewing all articles
Browse latest Browse all 841

Trending Articles