はじめに
本記事は以下記事で使用したOffice Scriptを学習する記事です。
上記の記事では、Microsoft Learnのサンプルコードを使用しています。
CSVをExcelに変換するサンプルコードを学習したいと思います。
サンプルコード
CSVデータ分解(行単位)
CSVデータを一行ずつ分解して配列rowsに格納する処理です。
csv = csv.replace(/\r/g, "");
let rows = csv.split("\n");
改行がCRLF(\r\n)LF(\n)の2パターンあるので、先にReplace関数でCR(\r)を除去してから、LF(\n)で分割して配列rowsに行を格納しています。
replace関数の引数「/\r/g」のgは、TypeScriptの正規表現で、gを付ければ最後まで検索、付けなければ最初の1つだけを検索します。
正規表現
CSV の1行をセル単位に切り出すための正規表現です。
const csvMatchRegex = /(?:,|\n|^)("(?:(?:"")*[^"]*)*"|[^",\n]*|(?:\n|$))/g
カンマ区切りでセルに書き込む値を抽出しますが、クォート付き、クォート無しなど考慮するため以下の正規表現が使われています。
| 正規表現 | 意味 | 例 | 備考 |
|---|---|---|---|
| (?:,|\n|^) | カンマ「,」改行「\n」「先頭文字」のいずれかを検出 | Bob,25,Osakaの場合、→Bob(先頭)→25(カンマ)→Osaka(カンマ) | ?:は非キャプチャグループ |
| ("(?:(?:"")*[^"]*)*" | クォート付きフィールドを抽出 | "Tokyo, Japan","He said ""Hello"""の場合、→Tokyo, Japan→He said ""Hello"" | *は0回以上の繰り返し、""はダブルクォート。^"は否定のためダブルクォート以外 |
| [^",\n]* | クォート無しフィールドを抽出 | Tokyo, Japan,He said Helloの場合→ Tokyo→Japan→He said Hello | ダブルクォート、カンマ、改行以外の文字を0回以上抽出 |
| (?:\n|$)) | 「改行または文字列の末尾を抽出 | - | \nは改行、$は最後の文字 |
繰返し処理(CSVデータ行単位)
CSVデータを1行ずつ処理します
rows.forEach((value, index) => { });
forEachで配列rows(CSVデータの行格納)の各要素(各行)に対して1回ずつ実行します。
value(第1引数)には、CSVデータ1行分の内容が、index(第2引数)にはカウンタが入っています。
空行判定
CSVデータ1行分が空行かどうかを判定して、空行の場合はスキップします。
if (value.length > 0) { ... }
セルを抽出
CSVデータ1行分から正規表現「csvMatchRegex」でセルに格納する文字列を取得して配列rowに格納します 。
let row = value.match(csvMatchRegex);
先頭空文字判定
行の最初がカンマから始まっている場合、最初のフィールドは空になるので配列の先頭に""を追加します。
if (row[0].charAt(0) === ',') {
row.unshift("");
}
unshift関数は配列の先頭に要素を追加する関数です。
セル内容整形
先頭にカンマがあれば除去、先頭と末尾の両方ともダブルクォーテーションがある場合は除去します。
row.forEach((cell, index) => {
cell = cell.indexOf(",") === 0 ? cell.substring(1) : cell;
row[index] = cell.indexOf("\"") === 0 && cell.lastIndexOf("\"") === cell.length - 1 ? cell.substring(1, cell.length - 1) : cell;
});
三項演算子:条件式 ? 真の場合の値 : 偽の場合の値; を使用
| コード | 意味 |
|---|---|
| cell = cell.indexOf(",") === 0 ? cell.substring(1) : cell; | 文字列の先頭がカンマか判定。先頭がカンマなら除去、そうでなければセル内容を設定 |
| row[index] = cell.indexOf("\"") === 0 && cell.lastIndexOf("\"") === cell.length - 1 ? cell.substring(1, cell.length - 1) : cell; | 先頭と末尾がダブルクォーテーションか判定。両側がダブルクォーテーションであればクォートを除去、そうでなければセル内容を設定。 |
行書込み
1行分のデータを2次元配列にして、Excelの該当行に書込みます。
let data: string[][] = [];
data.push(row);
let range = sheet.getRangeByIndexes(index, 0, 1, data[0].length);
range.setValues(data);
setValues関数が行と列の2次元配列を受け取るため、string[][]としています。
push関数は配列の末尾に要素を追加します。
getRangeByIndexesはIndex(第1引数)には書込む開始行、0(第2引数)は開始列、1(第3引数)は行数、data[0].lengthは列数になります。
学習した所感
CSVはPower Queryで扱う場合はそうでもないかもしれませんが、Office Scriptで扱う場合は処理が複雑のように感じました。
forEachは配列を処理する方法として抑えたいと思います。
今度は、JSON→Excelファイルに変換するOffice Scriptを書いてみたいです。