Excel VBAをJavaScriptに翻訳 その6
Excel VBAをJavaScriptに翻訳 その6:
はじめに
前回は、VBAの構文解析する前提としてVBAの予約語の定義とあわせて翻訳のサンプルVBAを提示しました.今回は、VBA翻訳結果のJavaScriptをコーディングします。
このJavaScriptへの翻訳が後続の道しるべとしたいと考えています。
前提
- OS : Windows7以上
- PoweShellのターミナルで実行
- VSCodeでコード編集
- node.js環境構築済み
ExcelJSのインストール
Excelのブックを読み書きするために、npmからExcelJSをローカルにインストールします。npm install --save exceljs
JavaScriptへの翻訳
ExcelJSの特徴として読込が非同期のため考慮が必要です。// read from a file var workbook = new Excel.Workbook(); workbook.xlsx.readFile(filename) .then(function() { // use workbook });
前回準備したExcelのブックのセル(A1)の取得結果が以下になります。
[ { text: '徳川 家康(とくがわ いえやす、旧字体: 德川家康)または' }, { font: { size: 11, color: [Object], name: 'MS Pゴシック', family: 3, charset: 128, scheme: 'minor' }, text: '松平 元康' }, { font: { size: 11, name: 'MS Pゴシック', family: 3, charset: 128, scheme: 'minor' }, text: '(' }, { font: { size: 11, color: [Object], name: 'MS Pゴシック', family: 3, charset: 128, scheme: 'minor' }, text: 'まつだいら もとやす' }, { font: { size: 11, name: 'MS Pゴシック', family: 3, charset: 128, scheme: 'minor' }, text: ')' }, { font: { size: 11, color: [Object], name: 'MS Pゴシック', family: 2, scheme: 'minor' }, text: 'は、戦国時代から安土桃山時代にかけての武将・戦国大名[1]。江戸幕府の初代征夷大将軍[1]。三英傑の一人。「海道一の' }, { font: { size: 11, color: [Object], name: 'MS Pゴシック', family: 3, charset: 128, scheme: 'minor' }, text: '弓取り' }, { font: { size: 11, color: [Object], name: 'MS Pゴシック', family: 2, scheme: 'minor' }, text: '」の異名を持つ。' } ]
objectは { key : key, val: val } の 構造になっています。
color : [Object]
/* * Color フォント属性の設定色を返却 * @PARAM {any} : obj - font object * @Return {any} : color - color */ function Color(obj) { if (typeof obj == 'object') { var color = ''; for (key in obj) { if (key == 'color') { for (val in obj[key]) { if (val == 'argb') { color = obj[key][val]; } } } } return color; } else { return obj; } }
関数の制御は以下の構造になります。
function 関数名(引数1, 引数2) { return new Promise(function(resolve) { // asynchronous : 非同期処理 wb.xlsx.readFile(filePath).then(function() { let sh = wb.getWorksheet("Sheet1"); 処理.... ret = 処理結果; resolve(ret); }); }); } function ラッパー関数(引数1, 引数2) { return 関数名(引数1, 引数2).then(function(val) { return val; }); }
AnsColor : 問題取得関数
文字色が赤の文字を'□'に変換する関数を作成します。AnsColorがラッパー関数で、GetProblemがPromise関数になります。
/* * GetAns 問題取得 * @PARAM {any} : adrs - Cell Address * @PARAM {any} : cls - font Color * @Return {any} : resolve - Problem */ function GetProblem(adrs, clr) { return new Promise(function(resolve) { // asynchronous : 非同期 wb.xlsx.readFile(filePath).then(function() { let sh = wb.getWorksheet("Sheet1"); let cell = sh.getCell(adrs).value; let buf = ''; for (i = 0 ; i < cell.richText.length ; i++) { if (Color(cell.richText[i].font) == clr) { for ( j = 0 ; j < cell.richText[i].text.length ; j++) { buf = buf + '□'; } } else { buf = buf + cell.richText[i].text; } } resolve(buf); }); }); } function AnsColor(adrs, clr) { return GetProblem(adrs, clr).then(function(val) { return val; }); }
AnzColor : 解答取得
文字色が赤の文字列を取り出す関数を作成します。AnzColorがラッパー関数で、GetAnsがPromise関数になります。
/* * GetAns 解答取得 * @PARAM {any} : adrs - Cell Address * @PARAM {any} : cls - font Color * @Return {any} : resolve - Answer */ function GetAns(adrs, clr) { return new Promise(function(resolve) { // asynchronous : 非同期 wb.xlsx.readFile(filePath).then(function() { let sh = wb.getWorksheet("Sheet1"); let cell = sh.getCell(adrs).value; let buf = ''; for (i = 0 ; i < cell.richText.length ; i++) { if (Color(cell.richText[i].font) == clr) { buf = buf + "," + cell.richText[i].text; } } resolve(Mid(buf,2)); }); }); } /* * AnzColor 文字列より指定色の文字列を取得 * @PARAM {any} : adrs - Cell Address * @PARAM {any} : cls - font Color * @Return {any} : val - Answer */ function AnzColor(adrs, clr) { return GetAns(adrs, clr).then(function(val) { return val; }); }
ファイルヘッダーの宣言と他の関数
関数で共通で使用する変数を宣言します。Assert/AssertN/Left/Right/Mid関数も定義します。
const Excel = require('exceljs'); let wb = new Excel.Workbook(); const path = require('path'); let filePath = path.resolve(__dirname,'temp.xlsx');
tomexcel.js
上記の全ソースです。const Excel = require('exceljs'); let wb = new Excel.Workbook(); const path = require('path'); let filePath = path.resolve(__dirname,'temp.xlsx'); /* * Assert 引数有無判定 * @PARAM {any} : a - Message * @PARAM {any} : b - Character String */ function Assert(a, b) { if (!b) { console.log(a + " 引数がありません"); return true; } else { return false; } } /* * AssertN 引数数値判定 * @PARAM {any} : a - Message * @PARAM {any} : b - Numeric Value */ function AssertN(a, b) { if (Assert(a, b)) {return true;} if (isNaN(b)) { console.log(a + " 数値ではありません"); return true; } else { return false; } } /* * Left * @PARAM {any} : str - Character String * @PARAM {any} : size - Character Length */ function Left(str, size) { if (Assert("Left " + "str", str)) {return Err;} if (AssertN("Left " + "size", size)) {return Err;} let len = (str.length < size) ? str.length : size; return str.substring(0, len); } /* Right * @PARAM {any} : str - Character String * @PARAM {any} : size - Character Length */ function Right(str, size) { if (Assert("Right " + "str", str)) {return Err;} if (AssertN("Right " + "size", size)) {return Err;} let len = (str.length < size) ? size : str.length; return str.substr(len - size, size); } /* Mid * @PARAM {any} : str - Character String * @PARAM {any} : pos - Start Position * @PARAM {any} : size - Character Length */ function Mid(str, pos, size) { if (Assert("Mid " + "str", str)) {return Err;} if (AssertN("Mid " + "pos", pos)) {return Err;} // size指定あり if(size) {if (AssertN("Mid " + "size", size)) {return Err;}} let len = size + 1 || str.length - pos + 1; return str.substring(pos - 1, len + 1); } /* * Color フォント属性の設定色を返却 * @PARAM {any} : obj - font object * @Return {any} : color - color */ function Color(obj) { if (typeof obj == 'object') { let color = ''; for (key in obj) { if (key == 'color') { for (val in obj[key]) { if (val == 'argb') { color = obj[key][val]; } } } } return color; } else { return obj; } } /* * GetAns 問題取得 * @PARAM {any} : adrs - Cell Address * @PARAM {any} : cls - font Color * @Return {any} : resolve - Problem */ function GetProblem(adrs, clr) { return new Promise(function(resolve) { // asynchronous : 非同期 wb.xlsx.readFile(filePath).then(function() { let sh = wb.getWorksheet("Sheet1"); let cell = sh.getCell(adrs).value; let buf = ''; for (i = 0 ; i < cell.richText.length ; i++) { if (Color(cell.richText[i].font) == clr) { for ( j = 0 ; j < cell.richText[i].text.length ; j++) { buf = buf + '□'; } } else { buf = buf + cell.richText[i].text; } } resolve(buf); }); }); } function AnsColor(adrs, clr) { return GetProblem(adrs, clr).then(function(val) { return val; }); } /* * GetAns 解答取得 * @PARAM {any} : adrs - Cell Address * @PARAM {any} : cls - font Color * @Return {any} : resolve - Answer */ function GetAns(adrs, clr) { return new Promise(function(resolve) { // asynchronous : 非同期 wb.xlsx.readFile(filePath).then(function() { let sh = wb.getWorksheet("Sheet1"); let cell = sh.getCell(adrs).value; let buf = ''; for (i = 0 ; i < cell.richText.length ; i++) { if (Color(cell.richText[i].font) == clr) { buf = buf + "," + cell.richText[i].text; } } resolve(Mid(buf,2)); }); }); } /* * AnzColor 文字列より指定色の文字列を取得 * @PARAM {any} : adrs - Cell Address * @PARAM {any} : cls - font Color * @Return {any} : val - Answer */ function AnzColor(adrs, clr) { return GetAns(adrs, clr).then(function(val) { return val; }); } module.exports = { AnsColor: AnsColor, AnzColor: AnzColor };
runexcel.js
作成した関数を実行する処理を作成します。if( process.argv[2] == undefined || process.argv[3] == undefined ) { console.log( '引数を指定してください!' ); return; }; let f = require('./tomexcel.js'); f.AnsColor(process.argv[2], process.argv[3]).then(function(val) { console.log(val); }); f.AnzColor(process.argv[2], process.argv[3]).then(function(val) { console.log(val); });
実行結果
runexcel.jsの引数にセル(A1)と赤(FFFF0000)を指定します。PS C:\~\tom> node runexcel.js 'A1' 'FFFF0000' 徳川 家康(とくがわ いえやす、旧字体: 德川家康)または□□□□□(□□□□□□□□□□)は、戦国時代から安土桃山時代にかけての武将・戦国大名[1]。江戸幕府の初代征夷 大将軍[1]。三英傑の一人。「海道一の□□□」の異名を持つ。 松平 元康,まつだいら もとやす,弓取り PS C:\~\tom>
まとめ
ExcelJSを使用してExcelのブックを読込んで結果を取得するJavaScriptをコーディングしました。(試験が不十分のためバグがありあそうです)
なんとなく翻訳結果を作成してみました。これに至るようにVBAからの翻訳を設計してみます。
次回はブックを更新するコーディングをやります。
コメント
コメントを投稿