2017-01-29 2 views
-1

Ich habe eine find_replace Subroutine, die Parameter (Inhalt, find regex, ersetzen regex, Ergebnisvariable zum Speichern von Ergebnis). Ich benutze qr//, um sowohl den Regex zu finden als auch zu ersetzen. Find Regex funktioniert gut, aber die Replace Regex nicht.Verwenden Sie qr // zum Ersetzen von RegEx zu Unterroutine

$text = "11 22 33 44 55"; 
find_replace($text,qr/(33)(.*?)(55)/,qr/$1<BOLD>$2<\/BOLD>$3/,my $newText); 
print $newText; 
    #Should print: 11 22 <I>33 <B>44</B> 55</I> 
    #But it prints: 11 22 <I>(?^:<B></B>)</I> 

sub find_replace { 
    my $content = shift; 
    my $findRegEx = shift; 
    my $replaceRegEx = shift; 
    my $newVariable = \shift; 

    ${$newVariable} = $content; 
    ${$newVariable} =~ s/$findRegEx/<I>$replaceRegEx<\/I>/g; 
} 

Ich habe eine Lösung für dieses gefunden zu arbeiten:

$text = "11 22 33 44 55"; 
find_replace($text,qr/(33)(.*?)(55)/,sub{"$1<B>$2<\/B>$3"},my $newText); 
print $newText; 
    #Prints: 11 22 <I>33 <B>44</B> 55</I> 

sub find_replace { 
    my $content = shift; 
    my $findRegEx = shift; 
    my $replaceRegEx = shift; 
    my $newVariable = \shift; 

    ${$newVariable} = $content; 
    ${$newVariable} =~ s($findRegEx){ "<I>".$replaceRegEx->()."<\/I>" }ge; 
} 

Aber dieses Update verwendet sub{"…"} statt qr/…/. Nach was ich suche, ist, den qr// für das Übergeben des Ersatzregex weiter zu verwenden und das gleiche Ergebnis zu erhalten.

+4

Das Ersatzteil * ist kein Regex *. Versuche nicht, es zu einem zu machen. Der sub {} Weg ist der richtige Weg dies zu tun. – ysth

+0

Sehen Sie [diesen Beitrag] (http://stackoverflow.com/a/41280344/4653379) (zum Beispiel) für welche Arten von Dingen, die Sie tun müssen. Verwenden Sie den "sub" -Ansatz, den Sie entdeckt haben, das ist eine nette Art, mit regex zu arbeiten :) – zdim

+0

@zdim Dieser Code könnte durch die Verwendung von ['Data :: Munge :: replace'] (https://metacpan.org/pod/Data :: Munge # ersetzen-STRING, -REGEX, -REPLACEMENT, -FLAG). – melpomene

Antwort

1

Sie müssen verstehen, dass der Text im Ersetzen keine Regex ist, sondern eine Zeichenfolge, die interpoliert werden kann. Sie müssen also Dinge wie Ihre Problemumgehung tun, um die Interpolation zu verzögern, bis die Regex gegen die erforderliche Zeichenfolge ausgeführt wurde.

Das ist gesagt, wenn Ihr Sub ist so einfach wie das, ich bin mir nicht sicher, ob Sie es wirklich in ein Sub - der s Operator ist bereits ein Sub-Anruf, und Sie sind nur kompliziert Dinge. Es gibt natürlich Situationen, in denen Sie eine Regex oder was auch immer zu einem viel komplexeren Unterelement übergeben müssen, und das könnte eine gute Sache sein, aber Sie benötigen diese Art von verzögerter Interpolation, damit es funktioniert.

3

Zuerst macht die Verwendung von qr// für den Ersatzausdruck keinen Sinn, da der Ersetzungsausdruck kein Regex-Muster ist. qq// (doppelte Anführungszeichenfolge) und q// (einfache Anführungszeichenfolge) werden verwendet, um Zeichenfolgen zu konstruieren.

Das Hauptproblem ist, dass

s/$findRegEx/<I>$replaceRegEx<\/I>/g 

bedeutet

my $repl_expr = sub { qq/<I>$replaceRegEx<\/I>/ }; # Interpolates $replaceRegEx 
s/$findRegEx/ $repl_expr->() /eg 

aber Sie wollen wirklich

my $repl_expr = sub { qq/$1<B>$2<\/B>$3/ };   # Interpolates $1, $2 and $3 
s/$findRegEx/ $repl_expr->() /eg 

Wenn Sie von einer Zeichenkette beginnen müssen (zB der Ersatz Ausdruck kommt aus eine Konfigurationsdatei), dann können Sie erreichen, was Sie wollen mit den folgenden:

use String::Substitution qw(gsub_copy); 

my $newText = gsub_copy($text, qr/(33)(.*?)(55)/, '$1<BOLD>$2</BOLD>$3'); 
Verwandte Themen