5

したがって、私の Perl スクリプトは基本的に文字列を受け取り、次のように複数の検索と置換を実行してクリーンアップしようとします。

$text =~ s/<[^>]+>/ /g;
$text =~ s/\s+/ /g;
$text =~ s/[\(\{\[]\d+[\(\{\[]/ /g;
$text =~ s/\s+[<>]+\s+/\. /g;
$text =~ s/\s+/ /g;
$text =~ s/\.*\s*[\*|\#]+\s*([A-Z\"])/\. $1/g; # replace . **** Begin or . #### Begin or ) *The 
$text =~ s/\.\s*\([^\)]*\) ([A-Z])/\. $1/g; # . (blah blah) S... => . S...

ご覧のとおり、私は厄介な html を扱っており、それを打ち負かして提出する必要があります。

これを行うための、よりシンプルで審美的に魅力的な方法があることを願っています。上記と同じように見える約50行があります。

キーがコメントで、ハッシュが正規表現であるハッシュを使用して、この問題の 1 つのバージョンを解決しました。

%rxcheck = (
        'time of day'=>'\d+:\d+', 
    'starts with capital letters then a capital word'=>'^([A-Z]+\s)+[A-Z][a-z]',
    'ends with a single capital letter'=>'\b[A-Z]\.'
}

そして、これが私がそれを使用する方法です:

 foreach my $key (keys %rxcheck) {
if($snippet =~ /$rxcheck{ $key }/g){ blah blah  }
 }

キーが式であり、それを置換したいものを指しているハッシュを試してみると、問題が発生します...そしてその中に$ 1または$ 2があります。

%rxcheck2 = (
        '(\w) \"'=>'$1\"'
}

上記はこれを行うことです:

$snippet =~ s/(\w) \"/$1\"/g;

しかし、「$1」の部分を文字通り正規表現に渡すことはできないようです (それは正しい言葉だと思います... ' マークを使用したにもかかわらず、$1 が解釈されているようです)。

if($snippet =~ /$key/$rxcheck2{ $key }/g){  }

そして、それはうまくいきません。

だから2つの質問:

簡単: 多数の正規表現を簡単に編集できる方法で処理して、前に行をカット アンド ペーストするだけでなく、それらを変更および追加できるようにするにはどうすればよいですか?

より難しい:ハッシュ(または、たとえば、1)検索する部分、2)置換3)コメント、4)グローバル/大文字と小文字を区別しない修飾子など、含めたい複数の部分がある場合は配列)を使用してそれらを処理するにはどうすればよいですかそれは実際にこれを行う最も簡単な方法ですか?

ご協力いただきありがとうございます -

4

3 に答える 3

10

問題#1

個々の正規表現によって共有される構造があまりないように見えるため、実行したようにコマンドをリストするよりも単純で明確な方法はありません。このようなコードの繰り返しを減らすための一般的なアプローチの 1 つは、次のように言う代わりに に移行$textすることです。$_

$text =~ s/foo/bar/g;

あなたはただ言うことができます:

s/foo/bar/g;

これを行うための一般的なイディオムは、縮退for()ループをトピックライザーとして使用することです。

for($text)
{
  s/foo/bar/g;
  s/qux/meh/g;
  ...
}

このブロックのスコープは、 の既存の値を保持するため、 を明示的にize$_する必要はありません。local$_

この時点で、ほぼすべての非ボイラープレート文字を削除しました。理論上でも、どれだけ短くできるでしょうか?

あなたが本当に望んでいるのは (あなたの問題 2 が示唆するように)モジュラー性の改善、例えば、すべての正規表現を反復、報告、カウントする機能などでない限りです。

問題#2

構文を使用してqr//、置換の「検索」部分を引用できます。

my $search = qr/(<[^>]+>)/;
$str =~ s/$search/foo,$1,bar/;

しかし、「置換」部分を適切に引用する方法がわかりません。これもうまくいくと思っていましたqr//が、そうではありません。検討する価値のある 2 つの選択肢があります。

1.ループで使用eval()します。foreach これにより、現在の%rxcheck2ハッシュを保持できます。欠点: string の安全性について常に考慮する必要がありますeval()

2.無名サブルーチンの配列を使用します。

my @replacements = (
    sub { $_[0] =~ s/<[^>]+>/ /g; },
    sub { $_[0] =~ s/\s+/ /g; },
    sub { $_[0] =~ s/[\(\{\[]\d+[\(\{\[]/ /g; },
    sub { $_[0] =~ s/\s+[<>]+\s+/\. /g },
    sub { $_[0] =~ s/\s+/ /g; },
    sub { $_[0] =~ s/\.*\s*[\*|\#]+\s*([A-Z\"])/\. $1/g; },
    sub { $_[0] =~ s/\.\s*\([^\)]*\) ([A-Z])/\. $1/g; }
);

# Assume your data is in $_
foreach my $repl (@replacements) {
    &{$repl}($_);
}

もちろん、ハッシュとしてより有用なキーを使用して代わりにハッシュを使用することも、コメントやその他の情報を含む多値要素 (またはハッシュ値) を使用することもできます。

于 2009-05-09T16:56:29.753 に答える
4

ハッシュは順序付けられていないため、適切ではありません。2番目の配列にコンパイルされた正規表現とevalする文字列が含まれる配列の配列が見つかりました(実際には二重evalです)が最適に機能します:

#!/usr/bin/perl

use strict;
use warnings;

my @replace = (
    [ qr/(bar)/ => '"<$1>"' ],
    [ qr/foo/   => '"bar"'  ],
);

my $s = "foo bar baz foo bar baz";

for my $replace (@replace) {
    $s =~ s/$replace->[0]/$replace->[1]/gee;
}

print "$s\n";

j_random_hacker の 2 番目のソリューションは、私のソリューションよりもはるかに優れていると思います。/ee個々のサブルーチンは柔軟性が最も高く、私のソリューションよりも桁違いに高速です。

bar <bar> baz bar <bar> baz
bar <bar> baz bar <bar> baz
         Rate refs subs
refs  10288/s   -- -91%
subs 111348/s 982%   --

これらの数値を生成するコードは次のとおりです。

#!/usr/bin/perl

use strict;
use warnings;

use Benchmark;

my @subs = (
    sub { $_[0] =~ s/(bar)/<$1>/g },
    sub { $_[0] =~ s/foo/bar/g },
);

my @refs = (
    [ qr/(bar)/ => '"<$1>"' ],
    [ qr/foo/   => '"bar"'  ],
);

my %subs = (
    subs => sub {
        my $s = "foo bar baz foo bar baz";
        for my $sub (@subs) {
            $sub->($s);
        }
        return $s;
    },
    refs => sub {
        my $s = "foo bar baz foo bar baz";
        for my $ref (@refs) {
            $s =~ s/$ref->[0]/$ref->[1]/gee;
        }
        return $s;
    }
);

for my $sub (keys %subs) {
    print $subs{$sub}(), "\n";
}

Benchmark::cmpthese -1, \%subs;
于 2009-05-09T16:47:57.960 に答える
4

あなたはHTMLを扱っていると言います。あなたは今、これがつかの間の壊れやすい解決策とのほとんど負け戦であることを認識しています.

適切な HTML パーサーがあれば、作業が楽になります。HTML::Parserは使いにくいかもしれませんが、 CPANには他にも非常に便利なライブラリがあり、どのようにではなくをしようとしているのかを指定できればお勧めできます。

于 2009-05-09T17:09:37.993 に答える