5

n'th regex match の抽出に関する以前の質問からフォローアップすると、見つかった場合は、一致を置き換える必要があります。

/e抽出サブルーチンを定義して修飾子で代入して呼べないかと考えました。私は明らかに間違っていました (確かに、私はXY 問題を抱えていました)。

use strict;
use warnings;

sub extract_quoted { # à la codaddict

        my ($string, $index) = @_;
        while($string =~ /'(.*?)'/g) {
                $index--;
                return $1 if(! $index);
        }
        return;
}

my $string = "'How can I','use' 'PERL','to process this' 'line'";

extract_quoted ( $string, 3 );
$string =~ s/&extract_quoted($string,2)/'Perl'/e;

print $string; # Prints 'How can I','use' 'PERL','to process this' 'line'

もちろん、この手法には他にも多くの問題があります。

  • 異なる位置に同一の一致がある場合はどうなりますか?
  • 一致するものが見つからない場合はどうなりますか?

このような状況を踏まえて、これをどのように実装できるかを考えています。

4

5 に答える 5

4

編集: leonbloy が最初にこのソリューションを思いつきました。賛成票を投じたい場合は、最初に leonbloy に賛成票を投じてください。

leonbloyの(以前の)回答に多少触発されました:

$line = "'How can I','use' 'PERL' 'to process this';'line'";
$n = 3;
$replacement = "Perl";

print "Old line: $line\n";
$z = 0;
$line =~ s/'(.*?)'/++$z==$n ? "'$replacement'" : "'$1'"/ge;
print "New line: $line\n";

古い行: 'How can I','use' 'PERL' 'to process this';'line'
新しい行: 'How can I','use' 'Perl' 'to process this';'line'
于 2010-03-31T19:20:54.830 に答える
3

または、このように何かを行うことができます

use strict;
use warnings;

my $string = "'How can I','use' .... 'perl','to process this' 'line'";

my $cont =0;
sub replacen { # auxiliar function: replaces string if incremented counter equals $index
        my ($index,$original,$replacement) = @_;
        $cont++;
        return $cont == $index ? $replacement: $original;
}

#replace the $index n'th match (1-based counting) from $string by $rep
sub replace_quoted {
        my ($string, $index,$replacement) = @_;
        $cont = 0; # initialize match counter
        $string =~ s/'(.*?)'/replacen($index,$1,$replacement)/eg;
        return $string;
}

my $result = replace_quoted ( $string, 3 ,"PERL");
print "RESULT: $result\n";

「グローバル」な $cont 変数は少し醜く、洗練されている可能性がありますが、アイデアはわかります。

更新: よりコンパクトなバージョン:

use strict;
my $string = "'How can I','use' .... 'perl','to process this' 'line'";

#replace the $index n'th match (1-based counting) from $string by $replacement
sub replace_quoted {
        my ($string, $index,$replacement) = @_;
        my $cont = 0; # initialize match counter
        $string =~ s/'(.*?)'/$cont++ == $index ? $replacement : $1/eg;
        return $string;
}

my $result = replace_quoted ( $string, 3 ,"PERL");
print "RESULT: $result\n";
于 2010-03-31T19:26:32.660 に答える
0

以前の質問への回答を作り直し、n -1 回一致してから次のものを置き換えます。パターンをメモ化することで、貧弱な Perl が同じパターンを何度も再コンパイルする必要がなくなります。

my $_quoted = qr/'[^']+'/; # ' fix Stack Overflow highlighting
my %_cache;
sub replace_nth_quoted { 
  my($string,$index,$replace) = @_;
  my $pat = $_cache{$index} ||=
    qr/ ^
        (                    # $1
          (?:.*?$_quoted.*?) # match quoted substrings...
            {@{[$index-1]}}  # $index-1 times
        )
        $_quoted             # the ${index}th match
      /x;

  $string =~ s/$pat/$1$replace/;
  $string;
}

例えば

my $string = "'How can I','use' 'PERL','to process this' 'line'";
print replace_nth_quoted($string, 3, "'Perl'"), "\n";

出力

「この行」を処理するには、「どうすれば」、「Perl」を使用できますか
于 2010-04-01T15:19:04.153 に答える
0

perldoc perlvarを参照してください:

use strict; use warnings;

use Test::More tests => 5;

my %src = (
    q{'I want to' 'extract the word' 'PERL','from this string'}
    => q{'I want to' 'extract the word' 'Perl','from this string'},
    q{'What about', 'getting','PERL','from','here','?'}
    => q{'What about', 'getting','Perl','from','here','?'},
    q{'How can I','use' 'PERL','to process this' 'line'}
    => q{'How can I','use' 'Perl','to process this' 'line'},
    q{Invalid} => q{Invalid},
    q{'Another invalid string'} => q{'Another invalid string'}
);

while ( my ($src, $target) = each %src ) {
    ok($target eq subst_n($src, 3, 'Perl'), $src)
}

sub subst_n {
    my ($src, $index, $replacement) = @_;
    return $src unless $index > 0;
    while ( $src =~ /'.*?'/g ) {
        -- $index or return join(q{'},
            substr($src, 0, $-[0]),
            $replacement,
            substr($src, $+[0])
        );
    }
    return $src;
}

出力:

C:\Temp> pw
1..5
ok 1 - 「別の無効な文字列」
わかりました 2 - 「この行」を処理するには、「PERL」を「どのように使用すればよいですか」
OK 3 - 無効
わかりました 4 - 「何について」、「取得」、「PERL」、「から」、「ここ」、「?」
OK 5 - 「この文字列から」「PERL」という単語を「抽出したい」

もちろん、無効$indexが渡された場合、または必要な一致が見つからない場合にどうなるかを決定する必要があります。上記のコードで元の文字列を返すだけです。

于 2010-03-31T21:26:10.727 に答える
0

正規表現があなたが持っているものよりもそれほど複雑でない場合は、 aの後splitに編集と a を続けることができますjoin:

$line = "'How can I','use' 'PERL','to process this' 'line'";

$n = 3;
$new_text = "'Perl'";
@f = split /('.*?')/, $line;
# odd fields of @f contain regex matches
# even fields contain the text between matches
$f[2*$n-1] = $new_text;
$new_line = join '', @f;
于 2010-03-31T19:21:19.727 に答える