Frage

Hier ist ein Problem, auf das ich kürzlich gestoßen bin.Ich habe Attributzeichenfolgen des Formulars

"x=1 and y=abc and z=c4g and ..."

Einige Attribute haben numerische Werte, einige haben Alphawerte, einige sind gemischt, einige haben Datumswerte usw.

Jede Saite ist angeblich haben "x=someval and y=anotherval" am Anfang, aber manche nicht.Ich muss drei Dinge tun.

  1. Überprüfen Sie die Zeichenfolgen, um sicherzustellen, dass sie vorhanden sind x Und y.
  2. Analysieren Sie tatsächlich die Werte für x Und y.
  3. Holen Sie sich den Rest der Zeichenfolge.

Im Beispiel oben würde dies zu den folgenden Variablen führen:

$x = 1;
$y = "abc";
$remainder = "z=c4g and ..."

Meine Frage ist:Gibt es eine (einigermaßen) einfache Möglichkeit, diese zu analysieren? Und mit einem einzigen regulären Ausdruck validieren?d.h.:

if ($str =~ /someexpression/)
{
    $x = $1;
    $y = $2;
    $remainder = $3;
}

Beachten Sie, dass die Zeichenfolge bestehen kann aus nur x Und y Attribute.Dies ist eine gültige Zeichenfolge.

Ich werde meine Lösung als Antwort veröffentlichen, aber sie entspricht nicht meiner Präferenz für einen einzelnen regulären Ausdruck.

War es hilfreich?

Lösung

Ich bin nicht der Beste in regulären Ausdrücken, aber das hier scheint dem, was Sie suchen, ziemlich nahe zu kommen:

/x=(.+) and y=([^ ]+)( and (.*))?/

Außer Sie verwenden 1 $, 2 $ und 4 $.In Benutzung:

my @strs = ("x=1 and y=abc and z=c4g and w=v4l",
            "x=yes and y=no",
            "z=nox and w=noy");

foreach (@strs) {
    if ($_ =~ /x=(.+) and y=([^ ]+)( and (.*))?/) {
        $x = $1;
        $y = $2;
        $remainder = $4;
        print "x: $x; y: $y; remainder: $remainder\n";
    } else {
        print "Failed.\n";
    }
}

Ausgabe:

x: 1; y: abc; remainder: z=c4g and w=v4l
x: yes; y: no; remainder: 
Failed.

Dadurch entfällt natürlich eine umfangreiche Fehlerprüfung, und ich weiß nicht alles über Ihre Eingaben, aber das scheint zu funktionieren.

Andere Tipps

Angenommen, Sie möchten auch etwas mit den anderen Name=Wert-Paaren machen, würde ich es so machen (mit Perl Version 5.10):

use 5.10.0;
use strict;
use warnings;

my %hash;
while(
    $string =~ m{
       (?: ^ | \G )    # start of string or previous match
       \s*

       (?<key>   \w+ ) # word characters
       =
       (?<value> \S+ ) # non spaces

       \s*             # get to the start of the next match
       (?: and )?
    }xgi
){
    $hash{$+{key}} = $+{value};
}

# to make sure that x & y exist
die unless exists $hash{x} and exists $hash{y};

Auf älteren Perls (mindestens Perl 5.6);

use strict;
use warnings;

my %hash;
while(
    $string =~ m{
       (?: ^ | \G )   # start of string or previous match
       \s*

       ( \w+ ) = ( \S+ )

       \s*            # get to the start of the next match
       (?: and )?
    }xgi
){
    $hash{$1} = $2;
}

# to make sure that x & y exist
die unless exists $hash{x} and exists $hash{y};

Diese haben den zusätzlichen Vorteil, dass Sie weiterarbeiten können, wenn Sie mit mehr Daten arbeiten müssen.

Als ziemlich einfache Modifikation von Rudds Version:

/^x=(.+) and y=([^ ]+)(?: and (.*))?/

ermöglicht Ihnen die Verwendung von $1, $2 und $3 (das ?:macht es zu einer nicht einfangenden Gruppe) und stellt sicher, dass die Zeichenfolge mit „x=" beginnt, anstatt eine Übereinstimmung mit „not_x=" zuzulassen

Wenn Sie die x- und y-Werte besser kennen, sollten Sie dies nutzen, um den regulären Ausdruck weiter zu verschärfen:

my @strs = ("x=1 and y=abc and z=c4g and w=v4l",
        "x=yes and y=no",
        "z=nox and w=noy",
        "not-x=nox and y=present",
        "x=yes and w='there is no and y=something arg here'");

foreach (@strs) {
    if ($_ =~ /^x=(.+) and y=([^ ]+)(?: and (.*))?/) {
        $x = $1;
        $y = $2;
        $remainder = $3;
        print "x: {$x}; y: {$y}; remainder: {$remainder}\n";
    } else {
        print "$_ Failed.\n";
    }
}

Ausgabe:

x: {1}; y: {abc}; remainder: {z=c4g and w=v4l}
x: {yes}; y: {no}; remainder: {}
z=nox and w=noy Failed.
not-x=nox and y=present Failed.
x: {yes and w='there is no}; y: {something}; remainder: {}

Beachten Sie, dass der fehlende Teil des letzten Tests darauf zurückzuführen ist, dass die aktuelle Version des y-Tests keine Leerzeichen erfordert. Wenn der x-Test dieselbe Einschränkung hätte, wäre diese Zeichenfolge fehlgeschlagen.

Rudd und Cebjyre haben Ihnen den größten Teil des Weges gebracht, aber beide haben bestimmte Probleme:

Rudd schlug vor:

/x=(.+) und y=([^ ]+)( und (.*))?/

Cebjyre hat es wie folgt geändert:

/^x=(.+) und y=([^ ]+)(?:Und (.*))?/

Die zweite Version ist besser, weil sie „not_x=foo“ nicht mit „x=foo“ verwechselt, sondern Dinge wie „x=foo z=bar y=baz“ akzeptiert und $1 = „foo z=bar“ setzt unerwünscht.

Das ist wahrscheinlich das, wonach Sie suchen:

/^x=(\w+) und y=(\w+)(?:Und (.*))?/

Dies verbietet alles zwischen den Optionen x= und y=, platziert und erlaubt das optionale „and…“, das in $3 enthalten sein wird

Hier ist im Grunde, was ich getan habe, um das Problem zu lösen:

($x_str, $y_str, $remainder) = split(/ and /, $str, 3);

if ($x_str !~ /x=(.*)/)
{
    # error
}

$x = $1;

if ($y_str !~ /y=(.*)/)
{
    # error
}

$y = $1;

Ich habe einige zusätzliche Validierungs- und Fehlerbehandlungsschritte weggelassen.Diese Technik funktioniert, ist aber nicht so prägnant oder hübsch, wie ich es mir gewünscht hätte.Ich hoffe, dass jemand einen besseren Vorschlag für mich hat.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top