お世話になっております。horagaiです。質問160286
http://oshiete1.goo.ne.jp/kotaeru.php3?q=160286
と同じようなことをやりたかったので回答#2のやり方を
試してみました。そこでいろいろ疑問が出てきたので教えていただきたいと思います。

(1)

$num=<> ;
while($num =~ s/(.*\d)(\d\d\d)/$1,$2/g){;}
print "num=$num\n";

とするとたしかにうまくいくのですが、これでうまくいく理由がわかりません。
置換演算子が後ろからパターンマッチをしていくのだとすればわかるのですが。
前からだとするとたとえば123456は最初に(1)(234)56で引っかかって1,23456 。
次に (1,2)(345)6 で引っかかって1,2,3456 ・・・。
などとなりそうな気がします。

(2)
またwhileを使わずに

$num =~ s/(.*\d)(\d\d\d)/$1,$2/g;

としてみると 例えば入力が 12345678 とすると
num=12345,678
と最初の3桁しか区切ってくれません。マニュアルを見ると
「gオプションは出現したパターンをすべて置換する。」
と書いてあるのにどうしてでしょう。
前からマッチするせよ後ろからマッチするにせよカンマが1つしか
入らないということはないと思うのですが。

以上、私が根本的な勘違いをしているかも知れませんので
その辺のところもご指摘いただければ幸いです。
ちなみにOSはLinux.Perlのバージョンは5.004です。

このQ&Aに関連する最新のQ&A

A 回答 (3件)

 えとですね。


 正規表現には1つの原則がありまして。

 たとえば、123456789だと、可能性として、

  1,23456789
  12,3456789
  123,456789
  1234,56789
  12345,6789
  123456,789

 これらすべて、マッチする可能性がありますよね。
 そういうパターンであることはわかりますか?

 で、正規表現は、「マッチする可能性の中から、もっとも文字列の長いものを採用する」という原則があります。
 ですので、.* にひっかかる可能性のあるうちで、もっとも長い文字列である 12345 がひっかかってるわけです。

 これは正規表現すべてで統一されていて、最長マッチといいます。
 逆に、もっとも短い可能性を採用させるには、

  (.*?\d)(\d\d\d)

 と、* のあとに ? を記述します。
 もっとも、これをやってもおっしゃったような状況にはならず、

  1,2345,6789

 になりますが。
 (これは、一度置き換えの対象になった部分は二度と検索しないという規則があるからです)

この回答への補足

な~るほど。質問の件についてはよーくわかりました。

>これらすべて、マッチする可能性がありますよね。
>そういうパターンであることはわかりますか?
もちろんわかります。だから置換演算子が前からマッチさせていくとすると
うまく行く理由がわからなかったのです。

>「マッチする可能性の中から、もっとも文字列の長いものを採用する」
>という原則があります。
この原則は知りませんでした。とにかく前から1文字ずつ読んでいって、マッチする
パターンが最初に出現した時点で即置換するものだとばかり思っていましたが、
一度最後まで読んでからパターン検出をするのですね。

ですがこの原則はあくまで長さが不定のパターンに対する原則ですよね。
長さが一定になるようなパターンなら、例えば(\d\d)(\d\d\d)などであれば
やはりパターンが最初に出現した部分にマッチすると考えてよいのでしょうか?
また正規表現の上では長さ不定でも、たまたま与えられた文字列ではそのパターンに
マッチするすべての場所が同じ長さになってしまった場合はどうなるのでしょう。
その場合も最初に出現した部分にマッチするのでしょうか?

>一度置き換えの対象になった部分は二度と検索しないという規則があるからです
なるほど。それで(2)の疑問、すなわちgオプションを付けても一度しか置換して
くれない理由もわかりました。
最初に
「マッチする可能性の中から、もっとも文字列の長いものを採用する」
という原則にしたがって (12345)(678) でマッチさせ (12345),(678)とする。
すると (12345,678)はすでに置き換えられた部分だから検索対象にならない。
よって残っているのは空文字列なので置換演算は終了する。
というわけですね。
whileを使うとうまく行くのは、一回置換するごとに新しい変数として扱われるので
また最初から全部検索してくれるため。
というわけですね。
そういう解釈であっていますか?

補足日時:2001/11/01 13:13
    • good
    • 0

 leaz024さんに補足していただいているようですが念のため。



>長さが一定になるようなパターンなら
 はい。
 実際に試してみました。必ず先頭からです。
 最後に $ を付けたら最後からになるかと思ったんですが、やってみたらやっぱり先頭からでした。
 ですので、正規表現の検索は必ず先頭からってことになるようです。

>そういう解釈であっていますか?
 これも合ってます。はい。
    • good
    • 0
この回答へのお礼

いろいろとありがとうございました。
いままで掲示板ソフトなどで置換演算子を使ってみてもなかなか思い通りの
置換をしてくれず、その理由がわからなくて悩んでいたのですが
「マッチする可能性の中から、もっとも文字列の長いものを採用する」
「一度置き換えの対象になった部分は二度と検索しない」
の2つの原則を知っただけで置換演算子の振舞の謎はほとんど解けました。
おかげさまでこれからは悩むことも減りそうです。
また何かありましたら宜しくお願いします。

お礼日時:2001/11/01 15:19

最長マッチについては、deagleさんのアドバイスでご理解頂けていると思います。



$num="1234567890"とすると、1回目のマッチングでは「1234567,890」となりますね。
s///は「置換した回数」(この場合1)を返すので、置換が成功するとwhileの条件が真となり、また置換を行おうとします。
この繰り返しで、2回目で「1234,567,890」、3回目で「1,234,567,890」となり、ここでマッチしなくなるためs///が0を返し、whileが終了します。

下記HPが大変参考になりますので、ご一読ください。

参考URL:http://www.din.or.jp/~ohzaki/perl.htm#NumberWith …
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
御紹介いただいたURLは知っていたのですが、「数字をコンマで区切る」
の項目には気がつきませんでした。たしかに参考になりました。
正規表現は奥が深いですね。

お礼日時:2001/11/01 15:38

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Q@b = grep(/マッチパターン/, @a);でなく@a = grep(/マッチパターン/, @a);でOKについて

@b = grep(/マッチパターン/,@a);だと配列@aの中でマッチするものを探して@bに入れる・・・というのは理解できるんですが、
@a = grep(/マッチパターン/,@a);とし、
foreach $_ (@a) {
print $_;
}
で参照した場合、@aの中のマッチパターンにマッチするのだけ表示されますけれども、ここでマッチしないのは削除されるのでしょうか・・。

@aから@aにいれる・・・となる事について、どのように@aにマッチしたものを入れ、マッチしないものは削除されるのかの仕組みについて、ご説明できる方はいらっしゃいますでしょうか(例えば内部的にpopやshiftが機能していて・・・みたいな事なのかな・・とか思うんですけれども)

お手数ですが、ご存知の先生方ご教授願えましたら幸いです。

Aベストアンサー

#1でのTacosanさんの回答の1です。
つまり、
@a = grep(/マッチパターン/,@a);
これは
@aの内容を列挙→ grepに掛ける→条件に合うものだけのリストを作成→作成したリストを代入。
となります。
grepに掛かる前の@aの内容は、代入の際に「丸ごと」破棄されます。

perly.y
/* Binary operators between terms */
termbinop:term ASSIGNOP term /* $x = $y */
{ $$ = newASSIGNOP(OPf_STACKED, $1, IVAL($2), $3);
TOKEN_GETMAD($2,$$,'o');
}

op.c

OP *
Perl_newASSIGNOP(pTHX_ I32 flags, OP *left, I32 optype, OP *right)
{
dVAR;
OP *o;

(略

if (is_list_assignment(left)) {
static const char no_list_state[] = "Initialization of state variables"


という具合なので、代入の左右両辺が同じ変数かどうかのチェックは多分やってません。

#1でのTacosanさんの回答の1です。
つまり、
@a = grep(/マッチパターン/,@a);
これは
@aの内容を列挙→ grepに掛ける→条件に合うものだけのリストを作成→作成したリストを代入。
となります。
grepに掛かる前の@aの内容は、代入の際に「丸ごと」破棄されます。

perly.y
/* Binary operators between terms */
termbinop:term ASSIGNOP term /* $x = $y */
{ $$ = newASSIGNOP(OPf_STACKED, $1, IVAL($2), $3);
TOKEN_GETMAD($2,$$,'o');
}

op.c

OP *
Perl_newASSIGNOP...続きを読む

Qperlスクリプト s/^\s+//;  s/\s+$//;  return wantarray ? @out : $out[0]; について

自作の掲示板を作ろうと思い、perlの勉強をしている者です。人様の作ったスクリプトを解析しています。以下のスクリプトはライブラリに記述されていたものです。


sub tttt {
my @out = @_;
for (@out) {
s/^\s+//;
s/\s+$//;
}
return wantarray ? @out : $out[0];


このスクリプトなんですが、 s/^\s+//; の部分の「+」と s/\s+$//; の部分の「+$」、 また「return wantarray~」 の三つの部分のスクリプトが、どういった働きをしているの分かりません。専門書やウェブ上のリファレンスも色々調べたのですが・・。

分かる方いらっしゃいましたらご教授下さると幸いです。よろしくお願いします。

Aベストアンサー

まず前2つの「+」は,正規表現における,「直前の表現を一回以上繰り返し」をあらわします.
「\s」は空白文字一文字を表す正規表現ですので,「\s+」は,「一文字以上の空白文字」になります.
次に,最初の「^」と2番目の「$」は,その正規表現がどこに現れるかを示す記号です.それぞれ,先頭と最後尾にあることを示します.
したがって,「^\s+」は,「最初に空白が一文字以上ある文字列」に,
「\s+$」は「行末に空白が一文字以上ある文字列」にヒットします.
置換構文sはご存知なんですかね.すなわち,この2文で,行の最初と最後の空白を消しているんです.

次に, wantarray ですが,
http://www2u.biglobe.ne.jp/~MAS/perl/ref/wantarray.html
によると,このサブルーチンttttを呼び出すときに,何を返り値にしているかで真偽が決まる関数です.
呼び出す時に配列を希望していたら @out 全体を,変数を希望していたら $out[0]だけを返します.

Q$wfurikae = 1 if ( &ccom::getShukujitsu( &com::tD( $wwy,$wwm,$wwd )) ne '' );がよく

$wfurikae = 1 if ( &ccom::getShukujitsu( &com::tD( $wwy,$wwm,$wwd )) ne '' );

というスクリプトがあったのですが、

$wfurikae = 1 の後に;もいれずifがきています。

違和感があります。

どのような意味になるのでしょうか。

宜しくお願い致します。

Aベストアンサー

そのまんまだと思いますよ。
if 以下の条件が真の時 $wfurikae = 1となります。
Perlはいろいろな書き方ができますので、こういう書き方もありです。
英語の文法の並びにする書き方です。

Q$hts =~ s/##([^#]+)##/$FORM{$1}/g の意味を教えてください!

お世話になります。
perl素人なのですが必要に迫られてWEBで調べながら
ソースを解析していますが、次のコードで完全に止まってしまいました。

$hts =~ s/##([^#]+)##/$FORM{$1}/g

この場合、
#hts から ##([^#]+)## を探して $FORM{$1} に全て置き換えようとしていると思うのですが、以下2点が理解できず困っています。

1.##([^#]+)## の意味
$htsに##で囲まれた文字列が複数あるのでそれら全てを探すということでしょうか?

2.$FORM{$1} の意味
$1は1.で検索した結果だと思いますが、$FORM{ }は一体なんでしょうか?

素人がいきなり解析するのは無謀なのは承知の上ですが、
どうしても業務で必要なので、お知恵をお貸し下さい。
よろしくお願いいたします。

Aベストアンサー

1.
perlを基準に「正規表現」で調べてごらん

2.
同じくperlでHTMLのformデータを受け取る方法を調べてごらん

Q「$" = ',';」という構文の意味は?

Perl スクリプト中に「$" = ',';」という構文が出てきたのですが、これはどういう意味ですか?

Aベストアンサー

"(ダブルクオート)内ではリスト値(@foo)も展開されますが、そのリスト値の区切り文字を定義する特殊変数で、デフォルトはスペースだそうです。

参考URL:http://www.tohoho-web.com/wwwperl1.htm#Tokushu


おすすめ情報