LoginSignup
15

More than 5 years have passed since last update.

「金額とか、カンマ区切りの数値をJSで。」のつづき。小数点も考えてみたんだけどね...。

Last updated at Posted at 2015-12-22

前回の復習から。

3桁区切りでカンマつけたいよね。というときの正規表現を教わったのがコレ。

金額とか、カンマ区切りの数値をJSで(正規表現を説明してもらった件)。

[該当する数値].toString().replace(/(\d)(?=(\d{3})+$)/g , '$1,');

ただ、コレって整数限定ですねー。っていうところで小数はどうだろう。ってモクモク考え続けたのがこのエントリーです。

正規表現にかぎらなかったらカンタンなんだよね。

ふつうに考えると、「小数点の前だけ置換したらえーやん」ってなります。

var targetNum = '123456789.123456789';
var delimiter = '.'; // 小数点。
var splitedNum = targetNum.toString().split(delimiter); // 小数点で区切っておいて
// 区切った前のとこだけ置換。それ以外は後から付け足し。
var replacedNum = splitedNum[0].replace(/(\d)(?=(\d{3})+$)/g , '$1,') + delimiter + splitedNum[1];

ね。ふつーでしょ?

正規表現だとできないの?

となると、一応、コレでもできる。

// 最初の$を(\.\d+)に変えた状態。「最後」を「小数点以下」に変えた感じ。
[該当する数値].toString().replace(/(\d)(?=(\d{3})+(\.\d+))/g , '$1,');

ただ、コレだと 小数値がある時限定 なのです。 「整数だけのとき。小数点以下がない時。」にはマッチしない のですよ...。

使う時には「整数だけ」でも「小数含んでる時」でも一緒に対応したいですよね。困った...。

or条件だとできないの?

とか、くるかなぁと思うんですけどね。

//「最後」か「小数点以下」でor条件にしたの。
[該当する数値].toString().replace(/(\d)(?=(\d{3})+($|\.\d+))/g , '$1,')

一見、よさそうなんですよ。ただですね...。

小数点以下もカンマ区切りされちゃう!

これは参った...。

これの回避をかなーり考えたのですが、

  1. 小数点の前、というのを一旦切り分ける
  2. 前に小数点がある、というのを認識する

のどちらかしか手がないのです。
正規表現的には1.はムリ。なので2.しかないんですけどね...。

もういっかい、/(?=(hoge))/を考える。

んで、前回教えてもらった/(?=(hoge))/

これ、「先読み」といわれるもので、x(?=y)の場合、 'x' に 'y' が続く場合のみ 'x' にマッチします

つまり、前回のは「数字3つ」の前にある「数字1つ」をマッチさせていたわけで、 さらにその前、というのは見つけられない のですね。

むーん。お手上げ。

ムリクリ「点の後ろに続いている数字1つ以上」をマッチさせようと思ったんですけど、それだと「1つ以上」が無限扱いされて、繰り返し拾うことができない。

色々やっては見たんですけど、ちょっとムリでしたわ...。

ま、何がなんでも正規表現のみでやらねばならぬ!!という機会とか、まぁないでしょうし...。

諦めて、関数つくっておしまいー。

もぅめんどくさくなって「小数点以下が3桁までってわかってたら↑でいーんじゃないのー?金額表記とか、ふつう小数点以下2桁だしー。2桁ならカンマ出ないやんー。」とかぶっちゃけ思ったりしたんですが、正規表現できないなら、代替する関数でも作っておこうかなと。

整数か小数かを見分けて、それぞれの正規表現で対応してみます。

function delimitNum(num){
    var delimiter = '.',
        numString = num.toString(),
        delimitExp = new RegExp('(\\d)(?=(\\d{3})+$)', 'g'), // 整数のときはこっちで置換。
        decimalDelimitExp = new RegExp('(\\d)(?=(\\d{3})+(\\.\\d+))', 'g'); // 小数のときはこっちで置換。

    function isDecimal() { // 整数か小数かをわけわけ。
        if(numString.indexOf(delimiter) > -1){
            return true;
        } else {
            return false;
        }
    }

    if(isDecimal()){  // 小数ですよ。って言われたら。
        return numString.replace(decimalDelimitExp, '$1,');
    } else { // 小数ですよ。って言われなかったら。
        return numString.replace(delimitExp, '$1,');
    }
}

先生〜。エスケープ文字がめんどくさいですー><。とか、小数点の前だけ置換して戻したらええやん。って思う場合は、

function delimitNum(num){
    var delimiter = '.',
        numString = num.toString(), 
        targetNum; // 置き換える文字列の置き場所を決めておこうかなと。

    function isDecimal() { // 整数か小数かをわけわけ。
        if(numString.indexOf(delimiter) > -1){
            return true;
        } else {
            return false;
        }
    }

    if(isDecimal()){ // 小数だったら、前と後ろを分けておく。
        targetNum = numString.split(delimiter);
    } else { // 整数だったらそのまま。
        targetNum = numString;
    }

    if(targetNum instanceof Array){ // わけわけされてたら、前を置換して、小数点付けて後ろをまるっと付け足し。
        return targetNum[0].replace(/(\d)(?=(\d{3})+$)/g , '$1,') + delimiter + targetNum[1];
    } else { // わけわけされてなかったら、そのまま置換。
        return targetNum.replace(/(\d)(?=(\d{3})+$)/g , '$1,')
    }
}

こんな感じですかねー...。私の頭だとこのくらいしか思い浮かばなかったです...。
正規表現得意な方、「こうすればー?」とかありましたらご助言おねがいしますーm(_"_)m

参考にさせていただきました。

正規表現 - JavaScript | MDN

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
15