ActionScript3で、数字3桁ごとにコンマを打つ正規表現について


num.toString().replace( /([0-9]+?)(?=(?:[0-9]{3})+$)/g , ‘$1,’ );
置換前)1234567899
置換後)1,234,567,899

正規表現を勉強中です。上記の文の意味(処理の流れ)、特に、下記にある「考えの評価・補足」をお願いしたいです。

・(?=(?:[0-9]{3})+$)は、「文字列の最後にある、ひとつ以上の「3桁の数字」以前の文字列にマッチして、なおかつこの文字はキャプチャしませんよ」という意味なのでしょうか?キャプチャさせないという理由はなんでしょう?$2を使わなければいいだけではないのでしょうか。

・流れとしては、上記の例でいくと「899」「567899」「2674567899」がそれぞれマッチするから、「1234567」「1234」「1」を後方参照(?)で$1としてコンマを語尾に付与、すべてをまとめてReplaceした結果が「1,234,567,899」?

ちょっと質問が多いですが、よろしくお願いします。

参考サイト
JavaScriptで数字3桁ごとにコンマを打つ
http://logic.stepserver.jp/data/archives/440.html

Python 2.4 クイックリファレンス
http://psyto.s26.xrea.com/python/PQR2.4/PQR2.4.ja.html

回答の条件
  • 1人3回まで
  • 登録:2009/03/31 21:04:23
  • 終了:2009/04/01 01:16:00

回答(3件)

id:susie-t No.1

susie-t回答回数99ベストアンサー獲得回数182009/03/31 22:34:12

ポイント34pt
$2を使わなければいいだけではないのでしょうか。

そのとおりです。理由としては、不要なキャプチャはしないほうが処理効率もいいですし(たぶん)、読む側も混乱しにくいからと思います。

「文字列の最後にある、ひとつ以上の「3桁の数字」以前の文字列にマッチして、なおかつこの文字はキャプチャしませんよ」

重要なのは「?=」が肯定の先読み(前方参照)である点です。

文章で説明するなら

「いくつかの数字が続き(←キャプチャ対象、小欲一致)、その後ろに3つの数字の繰り返しが最後まで続く(←先読み。当然ながらキャプチャ非対象)」

となります。

で、何が起こるかというと、

1,234567899→1,234,567899→1,234,567,899

となります。(gオプションを外してみてください。)

一回目、キャプチャ対象になるのは「1」、以降「234」、「567」です。

キャプチャ対象の「+?」は一回以上の繰り返し、ただし小欲一致(できる限り少ない一致)となります。

http://www.kt.rim.or.jp/~kbk/regex/regex.html

これで分かりますでしょうか。

id:kreuz2nd

早速のご回答ありがとうございます。参考URLとても勉強になります。ググってもこのサイトは見つからなかったので、ありがたいです。

$2を使わない理由はそういうことだったんですね。なるほど。

?=に関しては、恥ずかしながら先読みという意味を今初めて知りました(汗)。語弊があるかもしれませんが、先に読みにいくからそちらのほうが強い立場にあり、その前の部分を+?による小欲一致でキャプチャしてる、という感じなんでしょうか。

小欲一致というのも初めて知りました。これは使えますね。

ためしに[0-9]+?の?をとってみたら「1234567,\899」となりました。?=と同じくらいこれも重要みたいですね。

ただ、勉強が足りないせいか、流れがいまいちわからないです。

・先読みしたときに、ひとつ以上の「連続した3ケタ」を見つける -> 234/567/899がある

・キャプチャ部分が小欲一致なので、1のみがキャプチャされてコンマを付与

・1,234567899になる

・gオプションが付いてるから、一致するパターンを全部洗いだす

・次に一致するのが1,234だけど、正規表現で書いてるのは数字のみで、途中でコンマが入ってるから234のみがマッチして、234の後にコンマがつく

・1,234,567899になる

・567も同様

・1,234,567,899になって、「ひとつ以上の3桁の数字」の条件が合わなくなってしまったのでこれにて終了

こんな流れなんでしょうか。

2009/03/31 23:59:23
id:susie-t No.2

susie-t回答回数99ベストアンサー獲得回数182009/04/01 00:29:23

ポイント33pt

だいたいその認識であっていますが、ひとつ重要なことがあります。

正規表現のgオプションでの動作は、「一回検索した文字列は、以降(基本的に)検索対象としない」ということです。

なので、最初の検索が終了した時点で、以降の処理ではもう「1」は無視されます。検索は「2」から始まる、ということです。

ここで先読み、前方参照が重要になってきます。

先読みした場合、次回の検索は先読みした直前から始まるのです。

なので、今回の正規表現は、毎回最後まで検索するのですが、次回はキャプチャした文字列の次から検索するわけです。

(余談ですが、長い文字列に対して先読みを乱用すると、一気にパフォーマンスが下がる危険性があります。)

ただし、戻り読み、後方参照を使用すれば、前に戻って検索がかけられるのですが、

後方参照までサポートしている環境は少ないのが現状です。

(前方参照を駆使すれば事足りるケースが多いです。)

なので、2回目の検索対象文字列は「234567899」、キャプチャされるのは「234」、先読みされるのが「5678999」。

3回目は「5」から検索が始まります。

参考になれば幸いです。

id:kreuz2nd

>一回検索した文字列は、以降(基本的に)検索対象としない

なるほど!

「次に一致するのが1,234だけど、正規表現で書いてるのは数字のみで、途中でコンマが入ってるから234のみがマッチして、234の後にコンマがつく」っていうのは違って、「先読みしたから、今回の検索は前回の先読みの最初の文字の部分から検索が始まる」っていうことですね。で、gオプションだから「単に検索済みだから対象外」っていうのもあるけど、今回の正規表現の場合は先読みのほうがきいている、と。

gオプションはよくわからないままに使ってたので参考になります。

うーん、奥が深いですね。付け焼刃ではできそうにないというのが今回よくわかりました。1回じゃ覚えられそうにないので、明日反芻して自分のものにしたいと思います。

本当に参考になりました。ありがとうございました。

大変満足の回答が得られたので、これでこの質問への回答は終了させていただきます。

2009/04/01 01:14:25
id:susie-t No.3

susie-t回答回数99ベストアンサー獲得回数182009/04/01 00:58:43

ポイント33pt

すみません、大事なことを言い忘れました。

全部検索→全部置換 ではなくて、検索して、一回一致したら置換して、次の文字から再度検索、を繰り返すということです。

あと、

先読みした場合、次回の検索は先読みした直前→"その場所"から始まる、でした。すみません。

id:kreuz2nd

ご丁寧にありがとうございます。おかげさまでなんとなくわかった気がします。明日、最初の回答で教えてもらったURLで勉強したいと思います。

2009/04/01 01:15:12

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません