質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Perl

Perlは多目的に使用される実用性が高い動的プログラミング言語のひとつです。

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

置換

置換とは文字列中の特定の文字に対して、別の文字列に置き換えることを指します。

Q&A

解決済

3回答

4005閲覧

なぜ、$を付けるとカンマだらけにならなくなるのか

aaaaaaaa

総合スコア501

Perl

Perlは多目的に使用される実用性が高い動的プログラミング言語のひとつです。

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

置換

置換とは文字列中の特定の文字に対して、別の文字列に置き換えることを指します。

0グッド

4クリップ

投稿2016/05/19 11:25

編集2016/05/23 02:22

9ケタの数字、例えば「555555555」のような数字に3の倍数個ずつカンマを振り分ける際は、下記のように記述します。

s/(?<=\d)(?=(?:\d\d\d)+$)/,/

しかし、上記の数字がそれこそ「9ケタの数字、例えば「555555555」のような数字に3の倍数個ずつカンマを振り分ける際は、下記のように記述します。」という文章のように文字列の中に埋もれていた場合、
マッチしなくなります。マッチさせるために、末尾に三桁の数字、を意味する「$」を削除してしまうと、「えば「5,5,5,5,5,5,555」のような…」とカンマだらけになります。$が無くなったことで、残った条件が「左に数字、右に3の倍数個の数字」となるので、カンマだらけになる理由は、解かります。
疑問点は、なぜ$を消しただけでこのようにカンマだらけになってしまうのかです。
逆にいうと、なぜ末尾に三桁という条件を付けるとカンマだらけにならなくなるのかが解かりません。

ちなみに文字列中の数字にカンマをいれるときの正規表現は、「

s/(?<=d)(?=(?:\d\d\d)+)\b/,/

だと認識しております。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

s/(?<=\d)(?=(?:\d\d\d)+$)/,/

これの検索条件を日本語で表すと
「直前に数値が存在し、直後に1つ以上の”3桁の数値の塊り”が行末まで続くという条件を満たす”位置”」となります。(※文字は一つも指定されてないので位置ですね。)
例えば「555555555」の場合、「5」と「55555555」の間を見ると、”3桁の数値の塊り”が2つ続いたあと、末尾までに「55」が残りますので条件を満たしません。

行末記号を消した場合

s/(?<=\d)(?=(?:\d\d\d)+)/,/

「直前に数値が存在し、直後に1つ以上の”3桁の数値の塊り”が続くという条件を満たす”位置”」です。
「ここから555555555ここまで」の文字列を見ると、「ら」と「5」の間つまり数値の先頭には、その前に数値が無いので条件を満たしませんが、それ以降は条件を満たします。
例えば[5]と「55555555」の間を見ると、直前に数値があり、その後方には3桁以上の数値の塊りが1つ以上存在しています。
そして最後の3桁に入ると、後ろに3桁以上の数値が存在しなくなるので、条件を満たさなくなります。
従って「ここから5,5,5,5,5,5,555ここまで」こうなるでしょう。

文字列中の数字にカンマをいれるときの正規表現

s/(?<=\d)(?=(?:\d\d\d)+(\D|$))/,/g

※コメントで指摘いただき修正しました(5/24)
恐らくこんな感じ?
例によって日本語訳すると
「直前に数値が存在し、直後に1つ以上の”3桁の数値の塊り”が数値以外に行き当たるまで続くという条件を満たす”位置”」

投稿2016/05/19 13:13

編集2016/05/24 14:01
hirohiro

総合スコア2068

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

syockit

2016/05/24 10:25

gのフラグ忘れていませんか? ちなみに私なら`\D`の代わりに`(\D|$)`がいいかな。数字が文末にあっても当てはまるからです。
hirohiro

2016/05/24 14:00

仰るとおり両方必要ですね。 ご指摘ありがとうございます。
guest

0

Perlは文字列の可能な限り最も早い位置でマッチングを 行おうとします。

引用元

引用元にある通り、正規表現の基本挙動に従ってるだけです。

(/g の欠落は補完させて頂くとして)

s/(?<=\d)(?=(?:\d\d\d)+$)/,/g

の、(?=(?:\d\d\d)+$) が、3の倍数個の数字の連続が、(その時点での)最長になる位置を示すので、希望通りの挙動を示すのに対し、

後者は実質、

s/(?<=\d)(?=(?:\d\d\d))/,/g

と同じで、$ が無くなる事によって、最低3個の数字が連続する、最も最初の位置を示す事になりますので、一文字づつの置換となります。

投稿2016/05/21 22:13

bunzaemon

総合スコア118

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

マッチしていたら5の個数は減るはずですよね。結果を見ると文字間(0文字)にマッチしているようです。
先読み(<?=)・後読み(?=)の間の「本体にあたる部分」がないので、先読みの(<?=)を外せば意味を成すようになるのではないでしょうか。

,を複数入れるのでgオプションは必須です。
3桁ごとに一回の置き換えなので、(¥d¥d¥d)+とはできません。9桁でも,ひとつだけの出力になってしまいます。
元の文字は1文字も失わないようにするので、(?:)ではなく()を使って、後方参照できるようにします。

regex

1s/(¥d¥d¥d)(?=¥d)/$1,/g

でもこれだと「左から3桁ずつ」なので、よくないですね。
終端から先頭方向へマッチする表現が無いので、文字を逆順にするか、繰り返し処理する必要があると思います。

regex

1# 逆順にして置き換え処理 2$a = '「555555555」'; 3$a = reverse $a; 4$a =~ s/(\d\d\d)(?=\d)/$1,/g; 5$a = reverse $a; 6print $a;

regex

1# 繰り返し 2$a = '「555555555」'; 3while($a =~ s/(?<=\d)(\d\d\d)(?=\D)/,$1/){}; 4print $a;

投稿2016/05/24 04:50

編集2016/05/24 05:58
pmint

総合スコア33

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問