Frage

aus einer früheren Frage auf die n-te Regex extrahieren, muss ich jetzt das Spiel ersetzen, wenn gefunden.

Ich dachte, dass ich das Extraktionsunterprogramm definieren könnte und es in der Substitution mit dem /e Modifikator nennen. Ich war offensichtlich falsch (zugegebenermaßen, ich hatte einen XY Problem ).

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'

Es gibt natürlich viele andere Probleme mit dieser Technik:

  • Was, wenn es identische Übereinstimmungen an verschiedenen Positionen?
  • Was passiert, wenn das Spiel nicht gefunden wird?

In Anbetracht dieser Situation, ich frage mich, in welcher Weise diese umgesetzt werden könnten.

War es hilfreich?

Lösung

Oder Sie können etwas wie dies tun

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";

Ein wenig hässlich die "global" $ cont Variable, die poliert werden könnte, aber Sie bekommen die Idee.

Update: eine kompaktere Version:

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";

Andere Tipps

EDIT: leonbloy kam zum ersten Mal mit dieser Lösung auf. Wenn Ihr versucht, es zu upvote, erste upvote leonbloy Jahren.

Ein wenig inspiriert von leonbloy die (früher) Antwort:

$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";

Old line: 'How can I','use' 'PERL' 'to process this';'line'
New line: 'How can I','use' 'Perl' 'to process this';'line'

Wenn der Regex nicht zu viel komplizierter ist, als das, was Sie haben, Sie split mit einem Bearbeitungs folgen konnten und ein 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;

Siehe 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;
}

Ausgabe:

C:\Temp> pw
1..5
ok 1 - 'Another invalid string'
ok 2 - 'How can I','use' 'PERL','to process this' 'line'
ok 3 - Invalid
ok 4 - 'What about', 'getting','PERL','from','here','?'
ok 5 - 'I want to' 'extract the word' 'PERL','from this string'

Natürlich müssen Sie entscheiden, was passiert, wenn ein ungültiger $index geben wird oder wenn die erforderliche Übereinstimmung nicht gefunden wird. Ich kehre nur die Original-Zeichenkette in dem obigen Code.

nacharbeiten ein Antwort auf eine frühere Frage , match n -1 mal und dann die nächste ersetzen. Memoizing Muster Ersatzteile schlecht Perl die gleichen Muster immer und immer wieder neu kompilieren zu müssen.

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;
}

Zum Beispiel

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

Ausgänge

'How can I','use' 'Perl','to process this' 'line'
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top