LoginSignup
1
5

More than 1 year has passed since last update.

JavaScriptで漢数字や全角数字を半角数字に変換する

Last updated at Posted at 2021-07-06

概要

書き手が違うテキストを複数読み込むとき、全部半角数字にしてくれればいいのに、漢数字や全角数字が混在して困った経験はありませんか?私は大いに困りました・・・

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日

コメント頂いたコードを参考に、よりシンプルに修正しました。ありがたい。

1
5
2

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
1
5