メール フォルダから添付ファイルを抽出するプログラム ( GITHUB ) を作成しましたが、Perl の 32767 行の正規表現の制限により失敗します。私のプログラムは、各メール メッセージを 1 つの文字列として読み込み、base64 でエンコードされた各ファイルを 1 つの文字列として照合しようとします。
問題を再現するには、まず次のようにします。
(dd if=/dev/urandom bs=2000 count=1000 | base64 ; echo "\n\n\n" ; dd if=/dev/urandom bs=2000 count=1000 | base64 ) >! /tmp/testfile.txt
これにより、2 つのファイルの base64 エンコードを含む 5403516 バイトのファイルが 1 つ作成され、その間に 3 つの改行バッファーがあります。本番環境の状況はもう少し複雑ですが、この単純なケースが問題を示しています。
私たちの目標は、最初のファイルの base64 エンコーディングを抽出することです。つまり、50 文字以上で base64 文字のみを含む連続するすべての行ですが、最初の「=」記号 (base64 でファイルの終わりを示す) が表示されると停止します。
/tmp/testfile.txt には 70180 行あり、最初の 35088 行はキャプチャする文字列 (最初のファイルの base64 エンコード) を表しています。
Perl で次のことを行います。
# next 4 lines: read the entire file into a single variable
undef $/;
open(A,"/tmp/testfile.txt");
$all = <A>;
close(A);
# the output of base64 consists of these characters (plus "=" and
# "\n", but those two are special cases)
my($chars) = "[a-zA-Z0-9\+\/]";
# we declare a subroutine for testing
sub foo {print STDERR length($_[0]),"\n";}
# this is what I tried to do originally
$all=~s/(\n($chars{50,}\=*\n)+)($chars+\=*\n)/foo("$1$3")/seg;
上記は、「2523137」、「178467」、「2523137」、「178544」を STDERR に返します。
つまり、最初のファイルの最初の 2523137 文字をキャプチャし、最初のファイルの次の 178467 文字をキャプチャするのではなく、最初のファイルの 2701604 文字をすべてキャプチャします。2523137 は約 77*32767 であることに注意してください (また、/tmp/testfile.txt の各行の長さは 77 文字です)。
@ikegami、私が正しく理解していれば、あなたのアプローチは次のとおりです。
$all=~s/((\n($chars{50,}\=*\n){0,20000})+)($chars+\=*\n)//seg;
つまり、一度に 20000 行をキャプチャします (32767 行の制限を回避します) が、20000 行の複数の束をキャプチャします。これは正しいです?
結果は複数の変数で出力されるため、結果を foo() に渡しませんでしたが、代わりに次のように結果を STDERR に出力しました。
print STDERR "1 is $1\n";
print STDERR "2 is $2\n";
print STDERR "3 is $3\n";
print STDERR "4 is $4\n";
print STDERR "5 is $5\n";
print STDERR "6 is $6\n";
これにより、$1 と $2 が同一の 15085 行変数として生成され、$3 と $4 が同一でない 1 行変数として生成され、$5 と $6 が空として生成されます。
したがって、私はあなたのアプローチを誤解したと思います。ヘルプ?