2 my $tmp = $line;
3 $tmp =~ s/(?:\x0D\x0A|[\x0D\x0A])?$/,/;
4 @values = map {/^"(.*)"$/ ? scalar($_ = $1, s/""/"/g, $_) : $_}
5 ($tmp =~ /("[^"]*(?:""[^"]*)*"|[^,]*),/g);
6 }
2行目: 次の行で $line を変更するため、$line のコピーを $tmp に取る
3行目: 抽出処理を簡単にするため、最後の値の後ろにコンマを付加
$line の最後に改行コードがついていた場合、改行コードの削除
これで $line の中身は 値,値,値,・・・ の繰り返しになる
文末の0,1回の「¥x0D¥x0A」「¥x0D」「¥x0A」を「,」に置換
[正規表現] (?:abc) 後方参照不可のグループ化でメモリ節約
(hogehoge)? ()内に0or1回マッチ
4行目: 5行目で得られたリストの各要素に対する処理
# A ? B : C は、Aが真であればBを、偽であればCを値とします
# map例 @array2 = map { $_ + 10 } @array1; #全てに10を足した
# scalar例 $aaa = "111abc222";
# print scalar($_ = $aaa, s/abc/efg/g, $_); # 111efg222 が返る
# scalar関数は、()内の3命令を行った結果を返す(はじめて知った機能)
5行目: $tmpの中でマッチした文字列をすべて処理(4行目の map{ } が処理内容)
# $str ="a11nn44..55--aa";
# @w = ($tmp =‾ /¥d¥d/g); # 正規表現でマッチしたすべての文字列を @w に格納
# map {print $_,"¥n"} @w; # @w の各要素を改行つきで出力「11¥n44¥n55」
4,5行目の詳細解説
(1) 値,値,値, という形から個々の値を取り出すため修飾子 g をつけたパターンマッチを行う
( 修飾子 g をつけたパターンマッチをリストコンテキストで受けると、
( )によるグループにマッチした部分文字列のリストを返す )
パターン作成で注意が必要なのは,
「値,」、「 "値",」の 2種類があること
さらに「"値",」の方には、「,」、「""」が含まれている可能性があること
以下の場合ごとにパターンを作成し合成する
a.「値,」 の場合は、「,」が含まれないので、『/([^,]*),/』
b.「"値",」の場合は、値に「""」が含まれている可能性も考慮して
「[^"] 」と「""」の場合をあわせて、『/("(?:[^"]|"")*"),/』
a,bを合成して、『 /("(?:[^"]|"")*"|[^,]*),/g 』 となる
実行速度向上のために最適化を行い
($tmp =‾ /("[^"]*(?:""[^"]*)*"|[^,]*),/g); となる
「詳説正規表現」で「ループ展開」として書かれている手法で最適化
(2) map{ } の中では、
「値」 の形ならそのまま格納
「"値"」の形ならば両側の「"」を削除し、「""」を「"」に変換して格納