Weißes Rauschen

die meisten Blogs sind trauriges Geschwätz

Fußangel in Perl

Ein Problem, wenn beim Suchen und Ersetzen der Suchstring runde Klammern enthält, und die Lösung.

Eigentlich ganz einfach, ich habe zwei verschiedene Zeichenketten und möchte jeweils den Teil ab "a Camel" ersetzen. Mal klappt die Ersetzung, mal nicht. (Ich weiß, es geht in diesem Fall auch einfacher.)
#! /usr/bin/perl

use strict;
use warnings; 
use diagnostics;

my $EasyString = 'A string with a Camel Cigarette.';
my $ProblemString = 'A string with a Camel (Camelus bactrianus)!';

my @String = ($EasyString, $ProblemString, $EasyString, $ProblemString);

foreach my $string (@String)
{
	if ($string =~ /(a Camel.*).$/)	
	{
		my $CamelPart = $1;
		$string =~ s/$CamelPart/some Camel/;		
	}
	print $string, "\n";
}

Das Ergebnis:
A string with some Camel.
A string with a Camel (Camelus bactrianus)!
A string with some Camel.
A string with a Camel (Camelus bactrianus)!
Das Problem:
Sobald runde Klammern auf der linken Seite im Suchausdruck (s/Suchausdruck/Ersetzausdruck/) stehen, denkt perl, man möchte damit einen Teil aus dem Suchausdruck herausziehen und später mit $1 wiederverwenden. In der Zeile
if ($string =~ /(a Camel.*).$/) 
wollte ich das tatsächlich. Aber in der Zeile
$string =~ s/$CamelPart/some Camel/;
nicht, weil dann mein Suchausdruck nicht mehr passt. Perl sucht in diesem Fall nach "a Camel Camelus bactrianus", also ohne Klammern, und findet es nicht.

Die Lösung:
$string =~ s/\Q$CamelPart\E/some Camel/xms;
Zwischen \Q und \E werden alle Such-Sonderzeichen ignoriert, z.B.
. [ ] ( ) \s \n
etc. Damit werden auch die runden Klammern im Such-String nicht mehr als Sonderzeichen, sondern als normale Klammern interpretiert.
#! /usr/bin/perl

use strict;
use warnings; 
use diagnostics;

my $EasyString = 'A string with a Camel Cigarette';
my $ProblemString = 'A string with a Camel (Camelus bactrianus)';

my @String = ($EasyString, $ProblemString, $EasyString, $ProblemString);

foreach my $string (@String)
{
	if ($string =~ /(a Camel.*)/)	
	{
		my $CamelPart = $1;
		$string =~ s/\Q$CamelPart\E/some Camel/xms;
	}
	print $string, "\n";
}
Ergebnis:
A string with some Camel. 
A string with some Camel! 
A string with some Camel. 
A string with some Camel!

Alles ist gut.

PS: Dank an Wolfgang für den Hinweis auf \Q \E.

Weeeerbung!Lulzsec und Anonymous

Comments

Unregistered user Tuesday, July 26, 2011 8:41:35 AM

Wolfgang Kinkeldei writes: Schöner Artikel, der auf ein doch gelegentlich mal auftretendes Problem aufmerksam macht. Die Klammern sind ein Beispiel, aber Regular Expressions bestehen ja noch aus ein paar mehr Meta-Zeichen, die Du in Deine Ausnahme-Regelung mit aufnehmen müßtest... Genau dafür gibt es das Escape-Zeichen "\Q", mit dem Dir genau das nicht passiert :-) Diese Ersetzung sollte damit funktionieren ohne, daß Du $1 verändern mußt: $string =~ s{\Q$1\E}{some Camel}xms; perldoc perlre erklärt die ganze Geschichte.

SaschaEinSascha Tuesday, July 26, 2011 11:40:54 AM

Huch, das ist ja eine schnelle Reaktion. Ja danke. \Q und \E führen bei mir ein Schattendasein - zu unrecht wie man sieht. Ich passe das mal an.

How to use Quote function:

  1. Select some text
  2. Click on the Quote link

Write a comment

Comment
(BBcode and HTML is turned off for anonymous user comments.)

If you can't read the words, press the small reload icon.


Smilies