【JavaScript】全角数字または全角漢数字を半角数字に変換する
更新日:2023/06/27
ブラウザで数値を入力してもらうと全角になっていることが時々あります。
数値でないとアラートを出してもいいですが、半角数字に変換して続行した方がスマートに感じるケースもありますね。
JavaScriptで文字列内の全角数字を半角数字に変換する方法をお伝えします。
また、少し発展させて漢数字を半角数字に変換する方法もお伝えします。
全角数字を半角数字に変換
全角数字から半角数字への変換は、単純に正規表現で置換するだけですね。
const convertFullWidthNumbersToHalf = (()=>{
// 全角数字と半角数字の差分を計算
const diff = "0".charCodeAt(0) - "0".charCodeAt(0);
// 置換関数を返す
return text => text.replace(
/[0-9]/g
,m=>String.fromCharCode( m.charCodeAt(0) - diff )
);
})();
全角数値とマッチングする正規表現は、 /[0-9]/g です。
これで一文字だけマッチングします。
次に、コールバック関数でマッチした全角数字を半角数字に変換して、その結果を元の文字と置き換えています。
全角数字から半角数字への変換は、マッチ全角数字の文字コードから "0"(全角)の文字コードを引いて、"0"(半角)の文字コードを加算、最後に求めた値を文字列に変換します。
このコードは即時関数で全角数字と半角数字の差分(変数diff)を内部に閉じ込めています。
変数diffは固定値(0xFF10 - 0x0030)なので、この値を直接記述すれば即時関数は必要ありません。
しかし後でコードを確認したとき、入力した数値が正しいのかをもう一度確認する必要があります。
めんどくさいので文字コードの記述を避けた結果、即時関数を利用しています。
この関数をテストしてみます。
console.log( convertFullWidthNumbersToHalf("0123456") );
// 結果: 0123456
console.log( convertFullWidthNumbersToHalf("0123456") );
// 結果: 0123456
console.log( convertFullWidthNumbersToHalf("0123456") );
// 結果: 0123456
想定した結果になりました。
漢数字を半角数字に変換
漢数字から半角数字への変換は、少しメンドクサイです。
とりあえず、次のようなコードを作成しました。
const convertKanSujiToHalf = (()=>{
const numbers = [..."123456789"];
return text => text.replace(
/[一二三四五六七八九十百千万億兆京]+/g,
m=>Array.from([...m].reduceRight( (r,c)=>{
const keta = "十百千万億兆京".indexOf(c);
// 万億兆京
if( keta >= 3 ) {r.keta1 = ( keta - 2 ) * 4;r.keta2=0;return r;}
// 十百千
if( keta >= 0 ) {
r.keta2 = keta + 1;
r.result[ r.keta1 + r.keta2 ]="1";
return r;
}
r.result[ r.keta1 + r.keta2 ] = numbers[ "一二三四五六七八九".indexOf(c) ];
r.keta2++;
return r;
} , {keta1:0,keta2:0,result:[]}
).result,e=>e===undefined?"0":e).reverse().join("")
);
})();
文字列から漢数字を抜き出す正規表現は /[一二三四五六七八九十百千万億兆京]+/g です。
壱なども含まれるかもしれませんが、今回は対象外にしました。
文字列から全角数字を抜き出すときは [0-9] のように範囲指定できましたが、漢数字は文字と文字の間に他の文字が入っているので範囲指定できません。
なので、正規表現で全部記述します。
正規表現で取得した漢数字は[...m]で配列化した後、reduceRight()で後ろから処理していきます。
まず、"万"、"億"、"兆"などの一度のみ現れる桁文字が現れたら、対応する桁を記憶(r.keta1)します。
"万"なら0から数えて4、"億"なら8です。
次に複数回現れる桁文字、"十"、"百"、"千"が現れたら、対応する桁を記憶(r.keta2)します。
"十"は1、"百"は2です。
なお、100(百)や10(十)など前方に数値が無い可能性があるので、この時点で配列[ r.keta1 + r.keta2 ]に "1" をセットしておきます。
そして、"二"、"三"などの漢数字があらわれたら、配列[ r.keta1 + r.keta2 ]に、対応する半角数字をセットします。
セット後にr.keta2をインクリメント(+1)しています。
これにより、"一二三四五万" のように桁文字が抜けているとき、"12345000"と変換できるようにしています。
全ての文字を処理したら、Array.from()で配列の欠けているインデックスに"0"をセットします。
次に順番をリバースして、配列要素を文字列に連結して完了です。
では、テストしてみましょう。
console.log( convertKanSujiToHalf("百二十三兆四千五百六十七億八千九百一万二千三百四十五と二億一二三百万") );
// 結果: 123456789012345と223000000
console.log( convertKanSujiToHalf("一二三四五万") );
// 結果: 123450000
console.log( convertKanSujiToHalf("三億一二三四五万") );
// 結果: 323450000
このコードは桁文字の順番を考慮していないので、"二十万三億"なども処理します。
また "三十二万四十五万"など同じ桁位置が現れると、前方の値で上書きされます。
この場合は異なる数値として処理する方が自然かもしれませんね。
今回は「仕様」ということで、逃げます。
更新日:2023/06/27
関連記事
スポンサーリンク
記事の内容について
こんにちはけーちゃんです。
説明するのって難しいですね。
「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。
裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。
掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。
ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php
このサイトは、リンクフリーです。大歓迎です。