3 Stimmen

Wie kann ich eine in Anführungszeichen eingeschlossene Teilzeichenkette in Perl extrahieren?

Ich bin neu in Perl und reguläre Ausdrücke und ich habe eine harte Zeit, die Extraktion einer Zeichenfolge, die von doppelten Anführungszeichen eingeschlossen ist. Wie zum Beispiel,

"Stackoverflow is

awesome"

Bevor ich die Zeichenketten extrahiere, möchte ich prüfen, ob das Ende der Zeile des gesamten Textes in der Variablen enthalten ist:

if($wholeText =~ /\"$/)   #check the last character if " which is the end of the string
{
   $wholeText =~ s/\"(.*)\"/$1/;   #extract the string, removed the quotes
}

Mein Code hat nicht funktioniert; er gelangt nicht in die if Zustand.

2 Stimmen

Ein schneller Weg, um weniger als Noob zu erscheinen: die Sprache korrekt als Perl bezeichnen.

0 Stimmen

Danke, aber ich bin sehr verwirrt, weil mir jemand sagte, ich solle PERL statt Perl verwenden.

0 Stimmen

Irgendein Typ hat sich geirrt - es ist Perl.

9voto

chaos Punkte 118918

Das müssen Sie tun:

if($wholeText =~ /"$/)
{
    $wholeText =~ s/"(.*?)"/$1/s;
}

. stimmt nicht mit Zeilenumbrüchen überein, es sei denn, Sie wenden die /s Modifikator.

Es ist nicht nötig, die Anführungszeichen zu umgehen, wie Sie es tun.

4voto

Aaron Brown Punkte 249

Der obige Poster, der die Verwendung des "m"-Flags im regulären Ausdruck empfohlen hat, hat Recht, aber die bereitgestellte Regex wird nicht ganz funktionieren. Wenn Sie sagen:

$wholeText =~ s/\"(.*)\"/$1/m;   #extract the string, removed the quotes

...der reguläre Ausdruck ist zu "gierig", d.h. der (.*) Teil verschlingt zu viel Text. Wenn Sie ein Beispiel wie dieses haben:

"The quick brown fox," he said, "jumped over the lazy dog."

...dann wird die obige Regex alles von "The" bis "dog." erfassen, was wahrscheinlich nicht das ist, was Sie beabsichtigen. Es gibt zwei Möglichkeiten, die Regex weniger gierig zu machen. Welche davon besser ist, hängt ganz davon ab, wie Sie mit zusätzlichen " Markierungen in Ihrer Zeichenkette umgehen wollen.

Erstens:

$wholeText =~ s/\"([^"]*)\"/$1/m;

Zwei:

$wholeText =~ s/\"(.*?)\"/$1/m;

In One sagt die Regex: "Beginne mit quote, dann finde alles, was kein quote ist und merke es dir, bis du ein anderes quote siehst." In Zwei sagt die Regex: "Beginne mit quote, dann suche alles, bis du ein anderes Zitat findest." Das zusätzliche ? innerhalb des ( ) sagt dem Regex-Prozessor, dass er nicht gierig sein soll. Ohne Berücksichtigung der Anführungszeichen innerhalb der Zeichenkette sollten sich beide regulären Ausdrücke gleich verhalten.

Dies ist übrigens ein klassisches Problem beim Parsen einer CSV-Datei ("Comma Separated Values"), so dass es hilfreich sein kann, einige Referenzen dazu nachzuschlagen.

1 Stimmen

Ich glaube nicht, dass das /m das tut, was Sie denken, dass es tut. Wenn Sie die Anker ^ oder $ nicht in Ihrer Regex haben, bewirkt das /m nichts.

3voto

brian d foy Punkte 124323

Wenn Sie eine Übereinstimmung mit dem Ende der Zeichenfolge (nicht der Zeile, sondern der gesamten Zeichenfolge) verankern möchten, verwenden Sie die \z Anker:

 if( $wholeText =~ /"\z/ ) { ... }

Sie brauchen dafür keine Schutzbedingung. Verwenden Sie einfach die richtige Regex in der Ersetzung. Wenn sie nicht mit der Regex übereinstimmt, passiert nichts:

 $wholeText =~ s/"(.*?)"\z/$1/s;

Ich glaube, Sie haben eine ganz andere Frage. Warum versuchst du, sie am Ende der Schnur zu verankern? Welche Probleme wollen Sie vermeiden?

1voto

Jonathan Leffler Punkte 694013

Bei mehrzeiligen Zeichenfolgen müssen Sie den Modifikator 'm' in das Suchmuster aufnehmen.

if ($wholeText =~ m/\"$/m) # First m for match operator; second multi-line modifier
{
     $wholeText =~ s/\"(.*?)\"/$1/s;   #extract the string, removed the quotes
}

Sie müssen sich auch überlegen, ob Sie doppelte Anführungszeichen innerhalb der Zeichenkette zulassen und wenn ja, welche Konvention Sie verwenden wollen. Die wichtigsten sind Backslash und doppeltes Anführungszeichen (auch Backslash Backslash), oder doppeltes Anführungszeichen doppeltes Anführungszeichen in der Zeichenkette. Dadurch wird Ihre Regex etwas komplizierter.

Die Antwort von @chaos verwendet 's' als mehrzeiliges Modifikator . Es gibt einen kleinen Unterschied zwischen den beiden:

  • m

String als mehrere Zeilen behandeln. Das heißt, dass "^" und "$" nicht mehr auf den Anfang oder das Ende der Zeichenkette, sondern auf den Anfang oder das Ende einer beliebigen Zeile innerhalb der Zeichenkette zutreffen.

  • s

String als einzelne Zeile behandeln. Das heißt, "." so ändern, dass es auf jedes beliebige Zeichen passt, auch auf einen Zeilenumbruch, auf den es normalerweise nicht passen würde.

Wenn sie zusammen als /ms verwendet werden, kann das "." mit jedem beliebigen Zeichen übereinstimmen, während "^" und "$" nach bzw. vor Zeilenumbrüchen in der Zeichenkette übereinstimmen können.

0 Stimmen

@Brian: Was bedeutet das Fragezeichen im zweiten Ausdruck? AFAICS, bedeutet es 0 oder 1 der vorherigen Übereinstimmung von 0 oder mehr Zeichen...

0voto

xDimas Punkte 1

Angenommen, Sie haben eine einzelne Teilzeichenkette in Anführungszeichen, dann wird diese extrahiert:

s/. "(. ?)".*/$1/

Und die obige Antwort (s/"(.*?)"/$1/s) entfernt lediglich die Anführungszeichen.

Test-Code:

my $text = "no \"need this\" again, no\n";
my $text2 = $text;
print $text;
$text2 =~ s/.*\"(.*?)\".*/$1/;
print $text2;
$text =~ s/"(.*?)"/$1/s;
print $text;

Ausgabe:

no "need this" again, no
need this
no need this again, no

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X