5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Posted at

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

「受け取ったデータが.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のない朝は
今よりずっと素晴らしくて
すべての歯車が噛み合った
きっとそんな世界だ

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?