Perl覚え書き20041202

 この日の日記でちょこっと書いたけど、また質問しまくってるなあ…。なんか見てるとすごく歯がゆい。「その場所に飛んで行けたら5秒で解決するのに!」と思ってしまう。まあさすがに5秒は言い過ぎだけど。そんなにストレス溜まるのならやめればいいのになあ。

 それはさておき、今回のネタは例のアレ。ちょっとややこしい。プログラム的には大したことじゃないんだけど、正規表現がもうわけが分からない。自分でもよくわからなくなる。とりあえずソース。

 1: sub getToken {
 2: 	my $ref = shift;
 3: 	my $mode = shift;
 4: 	my $str = $$ref;
 5: 	my($token,$demi,$pre,$post);
 6: 	my $e = q{\\\\};
 7: 
 8: 	$str =~ s/^\s+//;
 9: 	if($mode) {
10: 		if($str =~ /^[^"'].*?(?<!$e)(?:$e$e)*(["'])/) {
11: 			$demi = $1 || $2;
12: 			$str = "$demi$str";
13: 		}
14: 	}
15: 	$str =~ m{^[^"'][^\s=>]+|^(["']).*?(?<!$e)($e$e)*\1};
16: 	$token = $&;
17: 	$post = $';
18: 	if($post =~ /^\s+=/) {
19: 		$demi = '=';
20: 		$post = $';
21: 	} else {
22: 		($demi) = $post =~ /^(.)/;
23: 		$post = $';
24: 	}
25: 	
26: 	$$ref = $post;
27: 	($token,$demi);
28: }

 まずは10行目。ここは$modeが0以外の時に実行される部分。呼び出し元が無いとよくわからないけどこの$modeは何かというとkey=valuevalue部分を処理するときに1とする。

 そしてここの部分の処理は、先頭が"か'ではないときにそれ以降に"や'が出てきた場合は、先頭に"か'が省略している物と見なし該当する物を補完するというもの。

 それがどうしてこんなややこしいものになっているかと言うと、\の存在。\"は"とは違う。それは読み飛ばしてしまおうと。またさらにややこしいことに、直前が\ではない"ということだと\\"にもマッチしてしまうがこれもまずい。これは\\と"という扱いにしなくてはならない。

 というわけで(\\\\)*["']という表現になる。$eが\\\\で$e$eとなるんだけど、変数に代入する時点で$eは\\になってしまう。それで($e$e)は(\\\\)になる。さらに正規表現の内容としては結局の所、\が二個を括弧で括って*だから、\が0個、2個、4個…というように偶数個の時にマッチする。

 15行目も内容はほとんど同じ。先頭が"か'で始まっていない場合は、スペースか=か>が出てきた時にトークンが終わったと見なす。

 もし"か'で始まっている場合にはさきほどの正規表現を用いて\の個数をチェックし、単体の"か'を見つけたらそこで終わりとする。書くまでもないが\1は(["'])の部分で開始部分が"と'のどちらで始まったかを保存してある。

 まあ他の所は特に難しそうな所はないと思うんで省略。

 …と、これを書いている途中で何やら不具合らしき物が見つかった気がする…。まだチェックしていないからわからないけど、たぶん間違いないだろう。まあ普通のちゃんとしたHTMLを通した場合は問題ないはず。

 んじゃまた。