やりたかったこと
| item | item1 | item2 | item3 |
|---|---|---|---|
| 単価 | 1,000 | 2,000 | 3,000 |
| 発注数 | 2 | 3 | 4 |
| 小計 | 2,000 | 6,000 | 12,000 |
↓
| item | item1 | item2 | item3 |
|---|---|---|---|
| 単価 | 1,000 | 2,000 | 3,000 |
| 発注数 | 5 | 3 | 4 |
| 小計 | 5,000 | 6,000 | 12,000 |
- 発注数が入力フォームになっている
- 単価と小計はフォームではなく、
<td>内の文字列 - フォームのchangeイベントで発火させて小計の計算を行い、3桁区切りの文字列として表示する
問題発生
カンマ区切りの文字列を数値に変換しようとするとカンマ以降の文字が捨てられてしまっていた
1,000 → 1
そのため、下記のような残念な状況に
| item | item1 | item2 | item3 |
|---|---|---|---|
| 単価 | 1,000 | 2,000 | 3,000 |
| 発注数 | 5 | 3 | 4 |
| 小計 | 5 | 6 | 12 |
対策
カンマがあるせいで数値扱いできないので
- カンマを削除する
- 計算する
- カンマを付け直す
の3ステップを踏むだけ。
ただし自分にとってはカンマを付け直すのが難問だった。
追記 2018.05.15
下にごちゃごちゃ書いてるけどもっとはるかに単純な方法があった。
var numberWithComma = new Intl.NumberFormat();
var price = 5000;
numberWithComma.format(price); // -> '5,000'
これだけでカンマ区切りの数値にできる。
コメントいただいたog24715さんありがとうございます。
というわけでここから下は正直蛇足。
実装
items.js
// カンマを削除し、数値に変換して扱えるようにする
var price = parseInt($("#item_price").text().replace(/,/g, ""));
var order_vol = parseInt($("#order_vol").text());
var subtotal_price = price * order_vol
// 正規表現で3桁ごとにカンマ区切りを挿入する
$("#subtotal_price").text(subtotal_price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','));
解説
カンマ区切りを挿入しているのは下記の部分
replace(/\B(?=(\d{3})+(?!\d))/g, ','));
こちらのサイトを参考にさせていただいてとりあえずの解決はしたが、何をしているのか理解するのに時間がかかったのでそれぞれの要素に分解してみる
メタ文字の意味
-
\B: 単語の境界以外の位置 -
(?=AAA): AAAという文字列の直前の位置を表す肯定の先読み -
(?!AAA): AAAではない文字列の直前の位置を表す否定の先読み -
\d: 1個の半角数字(0123456789) -
(pattern): グループ化 括弧内の文字列をひとつの塊として扱う -
{n}: 文字の個数を指定する -
+: 直前の文字が1文字以上
要素への分解
-
\B: 空白やカンマ、ピリオド、改行などの前後をマッチの対象から除外する -
(?=): 位置にマッチさせる -
(\d{3})+: 半角数字3つが一つ以上続く範囲にマッチさせる -
(?!\d): 数字以外の文字の直前を指定することで、空白やカンマ、ピリオド、改行などの直前から(数字の後ろの方から)マッチさせる
各正規表現でマッチする範囲または位置
位置にマッチする場合は^で表現する
| 正規表現 | 1000 | 1,000 | 1000000000 | 1000000.00 |
|---|---|---|---|---|
| (\d{3})+ | 100 | 000 | 100000000 | 100000 |
| (\d{3})+(?!\d) | 000 | 000 | 000000000 | 000000 |
| (?=(\d{3})+(?!\d)) | 1^000 | 1,^000 | 1^000^000^000 | 1^000^000.00 |
| \B(?=(\d{3})+(?!\d)) | 1^000 | なし | 1^000^000^000 | 1^000^000.00 |
一番下の正規表現では狙い通り数字の3桁区切りの位置にマッチしている事がわかる
感想
後ろからカウントする方法も3桁ごとにマッチさせる方法もさっぱり思いつかなかったけど要素に分解して1つずつ確認すると納得。
Rubular便利
数値に変換するときにカンマ以降の数が捨てられていたのはなんでなんだろうか。