#概要
書き手が違うテキストを複数読み込むとき、全部半角数字にしてくれればいいのに、漢数字や全角数字が混在して困った経験はありませんか?私は大いに困りました・・・
Web上に落ちてないかな~って軽く探しましたが、長大なコードばかりで複雑だなぁと思ったので、練習がてらに自分で作ってみました。
自分ではそこそこ簡潔に作れたかなと思ったのでアップしておきます。
もしもっとこうしたほうが簡単だよ、とか、バグがあれば、教えてください!w
#サンプルコード
function kan2num(str){
//
// 漢数字を半角数字に変換する関数
// cf. 二千三百五十 -> 2350
// 五十六億二十万千二百三円 -> 5600201203円
// 一五四七 -> 1547
// 2547百万 -> 2547000000
// 二十三万円はドルに直すと二千ドルくらい -> 230000円はドルに直すと2000ドルくらい
//
// str:String型
//
const m0 = { 0: "00〇零", 1: "11一壱", 2: "22二弐", 3: "33三参", 4: "44四",
5: "55五伍", 6: "66六", 7: "77七", 8: "88八", 9: "99九"}
const m1 = {1: "十拾", 2: "百", 3: "千仟阡"};
const m2 = {4: "万萬", 8:"億", 12:"兆"};
let stack1 = [], stack2 = [], trans = []; // stack:計算式を格納、trans:変換後の文字列を格納
let buf = str.split('');
let get_num = ch => {
for(let i in m0) if(ch.match(RegExp("[" + m0[i] + "]"))) return [i, "m0"];
for(let i in m1) if(ch.match(RegExp("[" + m1[i] + "]"))) return [10**i, "m1"];
for(let i in m2) if(ch.match(RegExp("[" + m2[i] + "]"))) return [10**i, "m2"];
return [ch, "str"];
}
// stack 内の計算式を全て計算して計算結果を trans に格納
let push_stack_to_trans = () => {
if(stack1.length) stack2.push((stack2.length ? "+": ""), String(eval(stack1.join(""))));
if(stack2.length) trans.push(String(eval(stack2.join(""))));
stack1=[], stack2=[];
}
for(let i=0; i<buf.length; i++){
let [ch, type] = get_num(buf[i]);
let type_b = i ? get_num(buf[i-1])[1] : ""; // 直前の文字のタイプ、i=0を除く
if(type != "str" && !stack1.length){ stack1.push(ch); continue;}
// 数字以外の文字の場合:stack1, 2を計算
if(type == "str"){
push_stack_to_trans();
trans.push(ch);
continue;
}
// 0~9の場合
if(type == "m0") (type_b == "m0") ? stack1.push(ch) : stack1.push("+", ch);
// 十、百、千などの場合
if(type == "m1") (type_b == "m0") ? stack1.push("*", ch) : stack1.push("+", ch);
// 万、億、兆などの場合:stack1の計算結果に掛けてstack2に格納
if(type == "m2"){
stack2.push((stack2.length ? "+": ""), String(eval(stack1.join(""))), "*", ch);
stack1 = [];
}
}
push_stack_to_trans();
return trans.join("");
}
#簡単な説明
数字の羅列を計算式に変換して、最後に計算させるというアルゴリズムです。
二千三百五十
= 2 * 1000 + 3 * 100 + 5 * 10
= 2350
五十六億二十万千二百三
= (5 * 10 + 6) * 100000000 + 2 * 10 * 1000 + 1000 + 2 * 100 + 3
= 5600201203
一五四七
= 1 5 4 7
= 1547
2547百万
= (2 5 4 7) * 1000000
= 2547000000
というように計算されています。
直前の文字によって + するのか * するのか、それとも何も演算子を入れないのかの分岐が若干ややこしくなっていますかね・・・
#追記
####2021年7月6日
早速修正。
\s
が0と認識されていたようなので、文字として認識するよう修正しました。
####2021年7月7日
コメント頂いたコードを参考に、よりシンプルに修正しました。ありがたい。