今回はNode.jsでExcelファイルを作成し、Excelを用いて原稿用紙に小説を流し込むというプログラムを作ってみましょう。万能ツールExcelとJavaScriptと組み合わせることで、原稿用紙に印字された趣のある読書体験が可能になります。
万能ツールExcelで原稿用紙を作成する方法
Excelは原稿用紙も作成できる万能ツールです。小説を原稿用紙に流し込んで読めないかなと思っていたところ、比較的簡単に実現できました。もちろん、Wordで実現することも可能ですが、Excelで作ればデザインが自由にカスタマイズできるので便利です。それで、今回は、Excelで次のような原稿用紙のブックを作ってみました。
ポイントは、まず、シート全体を選択して、全てのセルを適当なサイズに揃えておきます。そして、[Ctrl]キー(macは[command]キー)を押しながら1列空けて20個のヘッダを選択した状態で、メニューの[フォーマット > 列 > 幅]を指定して、適当な幅に揃えます。そして、罫線で茶色や緑色の線をつけます。これにより、原稿用紙の雰囲気を演出できます。
そして、このExcelブックを「genkouyousi.xlsx」という名前で保存します。今回は、このExcelファイルを利用したプログラムを作成します。こちらから素材とプログラムの一式をダウンロードできます。
JavaScriptを使ってExcelファイルを読み書きしよう
次に、JavaScriptでExcelファイルを読み書きする方法を確認してみましょう。今回は「xlsx-populate」というライブラリを使います。これを使えば、任意のセルに文字を書き込んだり、スタイルを変更したりできます。
ここでは、JavaScriptの実行エンジンであるNode.jsを利用します。こちらから、Node.jsのインストーラーをダウンロードしてインストールしましょう。
そして、Excelファイルを読み書きするライブラリ「xlsx-populate」をインストールしましょう。ターミナル(WindowsならPowerShell、macOSならターミナル.app)を起動して、次のコマンドを実行しましょう。
# プロジェクトを管理するディレクトリを作成する
mkdir program
cd program
# プロジェクトを作成してパッケージをインストール
npm -f init
npm install xlsx-populate
すると、package.jsonというファイルと、node_modulesというディレクトリが作成されます。これでNode.jsを使ったプロジェクトの準備が整いました。
ここで、このフォルダに「hello_excel.cjs」というファイルを作成して、次のようなプログラムを記述してみましょう。
// パッケージの取り込み
const XlsxPopulate = require('xlsx-populate')
// テンプレートのExcelブックを開く --- (*1)
XlsxPopulate.fromBlankAsync().then(workbook => {
// シートを取得 --- (*2)
const sheet = workbook.sheet(0)
// セルに値を設定 --- (*3)
sheet.cell("A1").value('能ある鷹は爪を隠す')
sheet.cell("A1").style('fontSize', 30)
workbook.toFileAsync('hello_excel.xlsx'); // ファイルに保存 --- (*4)
})
プログラムを実行しましょう。ターミナルで次のコマンドを実行します。
node hello_excel.cjs
すると、「hello_excel.xlsx」というExcelファイルが生成されます。これをExcelなどで開くと次のように表示されます。
プログラムを確認してみましょう。(*1)では、空のExcelブックを作成します。そして、(*2)で先頭のシートを取得します。(*3)ではセル「A1」に、ことわざを書き込み、フォントサイズを30に指定します。そして、最後に(*4)でファイルに保存します。
このように、xlsx-populateを使うと、手軽にExcelファイルを読み書きできます。
原稿用紙に小説データを流し込もう
xlsx-populateの基本が分かったところで、先ほど作成した原稿用紙を作成したExcelファイルを基にして小説を流し込むプログラムを作ってみましょう。
今回は、青空文庫にある夏目漱石の「吾輩は猫である」のテキストファイルを流し込んでみます。テキストファイル(ルビあり)のZIPファイルをダウンロードしたら、原稿用紙で読みやすくなるようにルビを削除して、文字エンコーディングUTF-8に変換しました。(変換済みのデータをサンプルファイルに梱包しています。)
それでは、テキストファイル「wagahaiwa_nekodearu.txt」を読み込み、原稿用紙に流し込むプログラムを作ってみましょう。縦書きの日本語は、右から左に流し込む必要があるため、列の右側42列目から左方向へ1列空けて書き込む必要があります。
それで、今回のプロジェクト構成は次のようなものになります。
.
├── genkouyousi.xlsx … 原稿用紙を作成したひな形のExcelファイル
├── kakikomi.cjs … メインプログラム
├── package.json … プロジェクト管理用ファイル
└── wagahaiwa_nekodearu.txt … 吾輩は猫であるのテキストファイル
それで、メインプログラム「kakikomi.cjs」は次のようになります。
// パッケージの取り込み
const XlsxPopulate = require('xlsx-populate')
const fs = require('fs')
// ファイル名を指定 --- (*1)
const TemplateExcelFile = './genkouyousi.xlsx'
const InputTextFile = './wagahaiwa_nekodearu.txt'
const OutputExcelFile = 'output_wagahai.xlsx'
// テンプレートのExcelブックを開く --- (*2)
XlsxPopulate.fromFileAsync(TemplateExcelFile).then(workbook => {
// テキストファイルを読む --- (*3)
const text = fs.readFileSync(InputTextFile, 'utf-8')
let row = 2
let col = 42
let page = 1
const nextLine = () => { // 改行処理 --- (*4)
row = 2
col = col - 2
if (col == 22) { col-- } // 原稿用紙の中央の列を避ける
if (col < 2) {
sheet = newPage()
col = 42
}
}
const newPage = () => { // 新しいシートを作成する処理 --- (*5)
const sheetName = `page${page++}`
console.log(sheetName)
workbook.cloneSheet(workbook.sheet("template"), sheetName, "template")
return workbook.sheet(sheetName)
}
let sheet = newPage()
// 1文字ずつテキストを原稿用紙に書き込む --- (*6)
for (let i = 0; i < text.length; i++) {
if (col <= 1) { break }
const ch = text.charAt(i)
if (ch === '\n') { // 改行の場合
nextLine()
if (page > 10) { break } // --- (*6a)
continue
}
const cell = sheet.row(row).cell(col)
cell.value(ch) // 文字を書き込む
row++
if (row >= 22) { nextLine() } // 改行処理
}
workbook.activeSheet('page1') // 1ページ目をアクティブに
workbook.toFileAsync(OutputExcelFile); // ファイルに保存 --- (*7)
})
上記のプログラムを「kakikomi.cjs」という名前で保存し、ターミナルから下記のコマンドを実行します。
node kakikomi.cjs
プログラムを実行すると、原稿用紙に吾輩は猫であるの小説が書き込まれ、「output_wagahai.xlsx」というExcelファイルを生成します。これをExcelで開くと次のように表示されます。
プログラムを見てみましょう。(*1)では各種ファイル名を指定します。(*2)では原稿用紙を作成したExcelブックを読み込みます。これをテンプレートとして利用します。