山括弧に配列を置くとグロブする
投稿:2018-11-08
このツイート/ブログを見て。
おおよそこんな感じ。
- perlop - Perl の演算子と優先順位 - perldoc.jp
- Perlの組み込み関数 glob の翻訳 - perldoc.jp
- File::Glob - Perl extension for BSD glob routine - metacpan.org
- スカラーコンテキストで山括弧の中のファイルハンドルを評価すると、 そのファイルから、次の行を読み込むことになります (改行があればそれも含まれます)。
- 山括弧の中の文字列がファイルハンドルでもファイルハンドル名、型グロブ、 型グロブリファレンスのいずれかが入った単純スカラ変数でもなければ、 グロブを行なうファイル名のパターンと解釈され、コンテキストによって ファイル名のリストか、そのリストの次のファイル名が返されます。
- 1 段階だけダブルクォート展開が行なわれます
- 引数を空白で分割して、それぞれを分割された パターンとして扱います
- 空でない中かっこが glob で使われている唯一の ワイルドカード文字列の場合、ファイル名とはマッチングせず、 可能性のある文字列が返されます。
Linuxのシェルで試すと一目瞭然です。
この記事を書くまで知らなかったです。
echo abc_{def,ghi}_jkl ↓ abc_def_jkl abc_ghi_jkl
まとめるとスペース区切りでワイルドカードを含まない文字列が返ってきます。
可能性として偶然ファイル名マッチングに一致したファイルがあれば、そのファイル名も返ってきます。
- <@soc> ←最初
- <"@soc"> ←ダブルクォート展開
- <'<!DOCTYPE html> <html lang="ja"> … </body> </html>'> ←配列の要素をスペース区切りで並べる
- '<!DOCTYPE', 'html>', '<html', 'lang="ja">', …, '</body>', '</html>' ←スペースで分割
- '<!DOCTYPE' ←呼ばれる度に1個ずつ
- 中カッコがある→組み合わせを展開
- ワイルドカードがある→ファイル名マッチングで見つかったファイル名を1個ずつ
- ワイルドカードがない→その文字列
うちのデスクトップ環境(Windows)にcurlがなく、LWP::UserAgentで代用しました。
#!/usr/bin/env perl -w use utf8; use strict; use warnings; use Data::Dumper; use Encode::Argv; use Encode::Locale; use LWP::UserAgent; use open IO => ":utf8"; binmode STDIN, ":encoding(console_in)"; binmode STDOUT, ":encoding(console_out)"; $| = 1; my $url = $ARGV[0] // "https://www.lemorin.jp"; print "URL:'$url'\n"; # curlコマンドの代わり my $ua = LWP::UserAgent->new; my $res = $ua->get($url); $res->is_success or die $res->status_line; my $buf = $res->decoded_content; my @soc = split /[\n\r]/, $buf; print "入力の要素数:@{[scalar @soc]}個\n"; my @reproduction = reproduction(@soc); print "再現の要素数:@{[scalar @reproduction]}個\n"; my @substitute = substitute(@soc); print "代用の要素数:@{[scalar @substitute]}個\n"; print "比較\n"; if (@reproduction == @substitute) { for (my $i = 0; $i < @reproduction; $i++) { print "${i}個目:'$reproduction[$i]' ne '$substitute[$i]'\n" if $reproduction[$i] ne $substitute[$i]; } } else { print "要素数不一致\n"; } print "グロブの展開を確認\n"; trial_glob(split //, "あいうえお"); trial_glob("abc{def,ghi}jkl"); trial_glob("abc def{ghi,jkl}mno pqr"); trial_glob("abc def{ghi,jkl}mno pqr*.txt"); trial_glob("abc", "def{ghi,jkl}mno", "pqr"); print "終了\n"; exit; sub reproduction { my @soc = map {Encode::encode locale => $_} @_; my @result; while ($buf = <@soc>) { push @result, Encode::decode locale => $buf; } return @result; } sub substitute { my @soc = map {Encode::encode locale => $_} @_; my @result; while ($buf = glob "@soc") { push @result, Encode::decode locale => $buf; } return @result; } sub trial_glob { my @a = @_; print "―――glob前―――\n"; for (@a) { print "$_\n"; $_ = Encode::encode locale => $_; } my @b = <@a>; print "―――結果―――\n"; for (@b) { my $c = Encode::decode locale => $_; print "$c\n"; } }
例によってWindowsとLinuxで同じ事を確認…ん、Linuxでは再現/代用の要素数が221個になりました(Windowsより1個多い)。
グロブの動作がOSに影響されているかもしれません。
URL:'https://www.lemorin.jp' 入力の要素数:76個 再現の要素数:220個 代用の要素数:220個 比較 グロブの展開を確認 ―――glob前――― あ い う え お ―――結果――― あ い う え お ―――glob前――― abc{def,ghi}jkl ―――結果――― abcdefjkl abcghijkl ―――glob前――― abc def{ghi,jkl}mno pqr ―――結果――― abc defghimno defjklmno pqr ―――glob前――― abc def{ghi,jkl}mno pqr*.txt ―――結果――― abc defghimno defjklmno ―――glob前――― abc def{ghi,jkl}mno pqr ―――結果――― abc defghimno defjklmno pqr 終了