4 Stimmen

Regex-Bereichsoperator

Ich habe eine Zeichenfolge '11 15'. Mit einer Regex vergleiche ich dann die Werte in dieser Zeichenfolge, in diesem Fall 11 und 15 (könnte eine beliebige Anzahl von Ziffern sein, aber ich halte es einfach mit 2 zweistelligen Zahlen).

Für jede dieser Zahlen prüfe ich dann, ob sie mit einer der gewünschten Zahlen übereinstimmt; in diesem Fall möchte ich sehen, ob die Zahl "12", "13" oder "14" ist. Wenn ja, dann ändere ich den Wert von "$m":

my $string = '11 15 ';
while ( $string =~ /([0-9]{1,})\s+/ig ) {
    my $m = $1;
    print $m . ".....";
    $m = 'change value' if $m =~ /[12...14]{2,}/g;
    print $m . "\n";
}

Produziert:

11.....change value
15.....15

Die "15" bleibt gleich, wie sie sein sollte. Aber '11' ändert sich. Was mache ich falsch?

4voto

Richard Simões Punkte 11699

[12...14] passt zu "1", "2", "." und "4". "11" stimmt damit überein, "15" nicht. Wenn Sie nur mit Zahlen übereinstimmen, sollten Sie keine regulären Ausdrücke verwenden. Ändern Sie Ihre Zeile in die folgende:

$m = 'change value' if $m ~~ [11..14];

Oder, wenn Sie Perl >= v5.10 nicht garantieren können:

$m = 'change value' if grep { $m == $_ } 11..14;

4voto

Adrian Pronk Punkte 12786

Sie haben den regulären Ausdruck missverstanden. Wo Sie geschrieben haben [12...14]{2,} Dies bedeutet "2 oder mehr der Zeichen 1 oder 2 oder Punkt oder Punkt oder Punkt oder Punkt oder 1 oder 4".

Versuchen Sie etwas wie:

$m='change value' if $m=~/(\d{2,})/ and $1 >= 12 and $1 <= 14;

In einer Substitutionsoperation könnte dies wie folgt geschrieben werden:

$m =~ s/(\d{2,})/ $1 >= 12 && $1 <= 14 ? 'change value' : $1/ge;

Das heißt, Sie erfassen 2 oder mehr Ziffern und testen dann die erfassten Ziffern, um zu sehen, ob sie das sind, was Sie ändern wollen, indem Sie Perl-Code im Ersetzungsteil der Substitution verwenden. Die e Modifikator zeigt an, dass Perl die Ersetzung als Perl-Code auswerten soll.

0voto

David W. Punkte 101611

Lassen Sie uns Ihren Code ein wenig umschreiben:

my $string = '11 15 ';
while ( $string =~ /(\d+)/g ) {

Ich habe Ihre while regulärer Ausdruck der Anweisung. Sie können verwenden \d+ um eine oder mehrere Ziffern darzustellen, und das ist einfacher zu verstehen als [0-9]{1,} . Sie können auch (da ein Leerzeichen nicht passt) \d ) brauchen das letzte Leerzeichen am Ende der Zeichenkette nicht.

Schauen wir uns nun den Rest des Codes an:

my $string = '11 15';
while ( $string =~ /(\d+)/g ) {
    my $match = $1;
    print "$match.....";
    if ($match >= 12 and $match <= 14) {   #if ($match ~~ [12..14]) for Perl > 5.10
        print 'change value\n';
    }
    else {
        print "$match\n";
    }
}

Sie können einen regulären Ausdruck nicht so verwenden, wie Sie es tun, um den Bereich zu prüfen.

Verwenden Sie stattdessen den regulären Reichweitentest von

if ($match >= 12 and $match <= 14)

oder das neuere Gruppentest :

if ($match ~~ [12..14])  #Note only two dots and not three!

Letzteres funktioniert nur mit neueren Perl-Versionen wie 5.12 auf meinem Mac und 5.14 auf meinem Linux-Rechner, aber nicht mit Perl 5.8 auf meinem Solaris-Rechner).

Ein paar Tipps:

  • Verwenden Sie Einzüge und Leerzeichen. Das macht Ihren Code besser lesbar.
  • Verwenden Sie beschreibende Namen für Variablen. Anstelle von $m habe ich $match .
  • Verwenden Sie nicht die angehängte if Erklärungen. Die beigefügten if ist schwieriger zu erkennen, so dass man etwas Wichtiges übersehen könnte, und es erschwert die Aktualisierung des Codes. Sie kann verwendet werden, wenn die Anweisung selbst klar und einfach ist, und sie verbessert die Lesbarkeit . Letzteres ist ein wenig subjektiv, aber Sie werden häufig folgende Anhänge sehen if Aussagen in Dingen wie return if not -f $file; .
  • Behalten Sie Variablen für einen einzigen Zweck. In diesem Fall wird statt der Änderung des Wertes von $match habe ich ein if/else Aussage. Stellen Sie sich vor, Ihr Code wäre etwas komplexer, und jemand müsste eine neue Funktion hinzufügen. Sie sehen die $match variabel und denken, dass sie genau das brauchen. Leider haben Sie geändert, was $match ist. Es handelt sich jetzt um einen Wert, der ausgedruckt wird, und nicht mehr um einen String-Match. Die Person, die Ihr Programm geändert hat, könnte eine ganze Weile brauchen, um herauszufinden, was mit dem Wert von $match und warum sie auf mysteriöse Weise auf changed value .
  • In der Druckanweisung können Sie Variablen in doppelte Anführungszeichen setzen. Das ist ein großer Unterschied zu fast allen anderen Sprachen. Der Grund dafür ist, dass Perl-Variablen Siegel um Variablennamen zu markieren. In der Regel ist es einfacher zu lesen, wenn Sie Variablen und andere Zeichenfolgen in einer einzigen Zeichenfolge zusammenfassen.

Zum Beispiel:

 print "The range of possible values are $low to $high\n";

vs.

 print "The range of possible values are " . $low . " to " . $high . "\n";

Beachten Sie, dass ich im zweiten Beispiel auf die Leerzeichen innerhalb der Anführungszeichen achten musste, während im ersten Beispiel die erforderlichen Leerzeichen ganz natürlich entstanden. Stellen Sie sich vor, Sie müssten diese Anweisung in einer späteren Version des Programms ändern. Was wäre leichter zu pflegen?

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