前回の復習から。
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.しかないんですけどね...。
もういっかい、/(?=(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