Bash、Perl、Regexを使ってテキストファイルから変数を抽出したいと思います。
ファイルは次のとおりです($ str変数が読み込まれました)。
Filename: XXXXX
Type: XXX
Size: XXXX
Unimportant thing: XXXX
Filename: YYYYY
Type: YYY
Size: YYYY
Unimportant thing: YYYY
各チャンクのファイル名、タイプ、サイズが必要です。配列は最適ですが、指定された文字で区切られたこれらの変数を含む文字列も受け入れられます。
ただし、一部のフィールド(サイズや種類など)がない場合があります。このレコードを省略したいので、複数行にわたって一致できる正規表現が必要なようです。
私は以下を試しました:
perl -pe 's/Filename: ([^\n]*)\nType: ([^\n]*)\nSize: ([^\n]*)\n/\1\t\2\t\3\n/' <<< $str
ただし、これは変更なしで元のテキストを印刷します。
その後、pコマンドライン引数なしで試しました(行を繰り返すのではなく、この方法でファイル全体を処理したいと思いました)。
perl -e 's/Filename: ([^\n]*)\nType: ([^\n]*)\nSize: ([^\n]*)\n/\1\t\2\t\3\n/' <<< $str
これは何も印刷しません(空の結果)。
その後、-pを削除すると、Perlが結果を印刷したいという事実を知らないかもしれないと思ったので、正規表現の前に印刷を追加しようとしました。
perl -e 'print s/Filename: ([^\n]*)\nType: ([^\n]*)\nSize: ([^\n]*)\n/\1\t\2\t\3\n/' <<< $str
それでも成功しませんでした(空の結果)。
私は何を見逃していますか?
修正する:
私はこれを1行のPerlコマンドとして欲しい。
ベストアンサー1
私のPerlの知識は弱いが、Perlに対する答えを知っている人がいないので試してみましょう。
データをファイルに渡すと、1行に3つの値がタブ区切りの行として印刷されます。
perl -e 'while (<>) { $s .= $_; } chomp $s; @arr = split(/\n{2,}/, $s); foreach my $a(@arr) { $a =~ s/Filename: ([^\n]*)\nType: ([^\n]*)\nSize: ([^\n]*)\n.*/$1\t$2\t$3\n/ || next; print "$a"; } ' infile
結果:
XXXXX XXX XXXX
YYYYY YYY YYYY
これはやや無差別的な方法ですが、入力を段落/ブロックに分割し、各段落/ブロックに複数行の正規表現を適用するように機能します。
詳細...
while (<>) { $s .= $_; }
- 入力を単一の文字列に変換します。chomp $s
- 文字列から末尾の改行文字を削除します。@arr = split(/\n{2,}/, $s)
- 連続した改行で文字列を分割します。これにより、段落/ブロックに分けられます。チャンクを配列に保存します。foreach my $a(@arr)
- 各配列要素(ブロック)を繰り返します。次の2行のコードが各ブロックに適用されます。$a =~ s/Filename: ([^\n]*)\nType: ([^\n]*)\nSize: ([^\n]*)\n.*/$1\t$2\t$3\n/ || next
- 関心のある3つの分野から値を抽出します。置換が発生しない場合(たとえば、値が欠落して正規表現が一致しないことを意味する場合)、このブロックをスキップして次のブロックに移動します。print "$a"
- 代替結果を印刷します。タブで区切られた3つの値。
しかし、私はPerlをあまり使用しないので、これよりもエレガントな解決策があるかもしれません。