/ / Regex, um das Feld mit der festen Länge mit dem gepackten Speicherplatz zu überprüfen - Regex

Regex zur Überprüfung des Feldes mit fester Länge und gepacktem Platz - Regex

Angenommen, ich muss eine Textdatei analysieren, die Inhalte mit fester Länge enthält:

123jackysee        45678887
456charliewong     32145644
<3><------16------><--8---> # Not part of the data.

Die ersten drei Zeichen sind ID, dann 16 Zeichen Benutzername, dann 8-stellige Telefonnummer.

Ich möchte einen regulären Ausdruck schreiben, der mit der Eingabe für jede Zeile übereinstimmt und diese überprüft, die ich mir ausgedacht habe:

(d{3})([A-Za-z ]{16})(d{8})

Der Benutzername sollte 8-16 Zeichen enthalten. Aber ([A-Za-z ]{16}) würde auch mit Nullwert oder Leerzeichen übereinstimmen. ich denke an ([A-Za-z]{8,16} {0,8}) aber es würde mehr als 16 Zeichen erkennen. Irgendwelche Vorschläge?

Antworten:

7 für die Antwort № 1

Nein nein Nein Nein! :-)

Warum bestehen die Leute darauf, so viele Funktionen in eine einzelne RE- oder SQL-Anweisung zu packen?

Mein Vorschlag, machen Sie etwas wie:

  • Stellen Sie sicher, dass die Länge 27 beträgt.
  • Extrahieren Sie die drei Komponenten in separate Zeichenfolgen (0-2, 3-18, 19-26).
  • Überprüfen Sie, ob die ersten übereinstimmen "d{3}".
  • Überprüfen Sie, ob die zweite übereinstimmt "[A-Za-z]{8,} *".
  • Überprüfen Sie, ob der dritte übereinstimmt "d{8}".

Wenn Sie möchten, dass der gesamte Scheck in eine Zeile des Quellcodes passt, fügen Sie ihn in eine Funktion ein. isValidLine()und nenne es.

Sogar so etwas würde den Trick machen:

def isValidLine(s):
if s.len() != 27 return false
return s.match("^d{3}[A-za-z]{8,} *d{8}$"):

Lassen Sie sich nicht täuschen, dass dies sauberes Python istCode, es ist eigentlich PaxLang, mein eigener proprietärer Pseudocode. Hoffentlich ist klar genug, dass die erste Zeile prüft, ob die Länge 27 ist, die zweite, dass sie mit dem angegebenen RE übereinstimmt.

Das mittlere Feld besteht automatisch aus 16 Zeicheninsgesamt aufgrund der ersten Zeile und der Tatsache, dass die beiden anderen Felder in der RE eine feste Länge haben. Der RE stellt außerdem sicher, dass es sich um acht oder mehr Alphas handelt, gefolgt von der richtigen Anzahl von Leerzeichen.

So etwas mit einem einzigen RE zu machen, wäre eine Monstrosität wie:

^d{3}(([A-za-z]{8} {8})
|([A-za-z]{9} {7})
|([A-za-z]{10} {6})
|([A-za-z]{11} {5})
|([A-za-z]{12}    )
|([A-za-z]{13}   )
|([A-za-z]{14}  )
|([A-za-z]{15} )
|([A-za-z]{16}))
d{8}$

Sie können dies tun, indem Sie sicherstellen, dass zwei bestanden werden trennen REs:

^d{3}[A-za-z]{8,} *d{8}$
^.{27}$

aber da es sich bei dem letzten lediglich um eine Längenprüfung handelt, unterscheidet es sich nicht von der isValidLine() über.


0 für die Antwort № 2

Ich würde den von Ihnen vorgeschlagenen regulären Ausdruck mit einem kleinen Zusatz verwenden:

(d{3})([A-Za-z]{3,16} {0,13})(d{8})

was zu Dingen passt, die eine habenNicht-Whitespace-Benutzername, aber dennoch Leerzeichen zulassen. Der einzige Zusatz ist, dass Sie dann die Länge jeder Eingabe überprüfen müssten, um die korrekte Anzahl von Zeichen zu überprüfen.


0 für die Antwort № 3

Hmm ... Abhängig von der genauen Version von Regex, die Sie ausführen, sollten Sie Folgendes berücksichtigen:

(?P<id>d{3})(?=[A-Za-zs]{16}d)(?P<username>[A-Za-z]{8,16})s*(?P<phone>d{8})

Beachten Sie 100% sicher, dass dies funktioniert, und ich habe das Leerzeichen-Escape-Zeichen anstelle eines tatsächlichen Leerzeichens verwendet. Ich werde nur mit dem Leerzeichen selbst nervös, aber Sie möchten möglicherweise restriktiver sein.

Überprüfen Sie, ob es funktioniert. Ich bin selbst nur zwischengeschaltet bei RegEx, daher kann es sein, dass ich mich irre.

Überprüfen Sie die benannte Gruppensyntax für Ihre Version von RegEx. A) existiert und b) entspricht dem oben verwendeten Standard.

BEARBEITEN:

Nur um zu erweitern, was ich versuche (sorry, dass deine Augen bluten, Pax!) Für diejenigen ohne viel RegEx-Erfahrung:

(?P<id>d{3})

Dadurch wird versucht, eine benannte Erfassungsgruppe abzugleichen."id" - das sind drei Ziffern. In den meisten Versionen von RegEx können Sie benannte Erfassungsgruppen verwenden, um die Werte zu extrahieren, mit denen Sie übereinstimmen. Auf diese Weise können Sie die Validierung und Datenerfassung durchführen gleichzeitig. Verschiedene Versionen von RegEx haben hierfür leicht unterschiedliche Syntaxen - sehen Sie sich das an http://www.regular-expressions.info/named.html Weitere Informationen zu Ihrer speziellen Implementierung.

(?=[A-Za-zs]{16}d)

Das? = Ist ein Lookahead-Operator.Dies sieht für die nächsten 16 Zeichen voraus und gibt true zurück, wenn es sich bei allen um Buchstaben oder Leerzeichen handelt UND auf die eine Ziffer folgt. Der Lookahead-Operator hat die Länge Null und gibt daher eigentlich nichts zurück. Ihre RegEx-Zeichenfolge wird ab dem Punkt fortgesetzt, an dem der Lookahead gestartet wurde http://www.regular-expressions.info/lookaround.html Weitere Informationen zu Lookahead.

(?P<username>[A-Za-z]{8,16})s*

Wenn der Lookahead vorbei ist, zählen wir weiterab dem vierten Zeichen in. Wir möchten acht bis sechzehn Zeichen finden, gefolgt von null oder mehr Leerzeichen. Das "oder mehr" ist tatsächlich sicher, da wir bereits im Lookahead sichergestellt haben, dass vor der nächsten Ziffer nicht mehr als 16 Zeichen stehen dürfen.

Endlich,

(?P<phone>d{8})

Dies sollte die achtstellige Telefonnummer überprüfen.

Ich bin etwas nervös, dass dies nicht genau funktioniert - Ihre Version von RegEx unterstützt möglicherweise nicht die benannte Gruppensyntax oder die Lookahead-Syntax, die ich gewohnt bin.

Ich bin auch etwas nervös, dass dieser Regex erfolgreich mit einer leeren Zeichenfolge übereinstimmt. Verschiedene Versionen von Regex behandeln leere Zeichenfolgen unterschiedlich.

Sie können auch in Betracht ziehen, diesen Regex zwischen a ^ und $ zu verankern, um sicherzustellen, dass Sie mit der gesamten Zeile und nicht nur mit einem Teil einer größeren Zeile übereinstimmen.


0 für die Antwort № 4

Angenommen, Sie meinen Perl-Regex und wenn Sie "_" im Benutzernamen zulassen:

perl -ne "exit 1, es sei denn / (d {3}) (w {8,16}) s + (d {8}) / && length == 28"

0 für die Antwort № 5

@OP, nicht jedes Problem benötigt eine Regex.dein Problem ist ziemlich einfach zu überprüfen. Je nachdem, welche Sprache Sie verwenden, haben sie eine Art eingebaute Zeichenfolgenfunktionen. benutze sie. Das folgende Minimalbeispiel ist in Python ausgeführt.

import sys
for line in open("file"):
line=line.strip()
# check first 3 char for digit
if not line[0:3].isdigit(): sys.exit()
# check length of username.
if len(line[3:18]) <8 or len(line[3:18]) > 16: sys.exit()
# check phone number length and whether they are digits.
if len(line[19:26]) == 8 and not line[19:26].isdigit(): sys.exit()
print line

0 für die Antwort № 6

Ich denke auch, dass Sie nicht versuchen sollten, alle Funktionen in eine einzige Regex zu packen. Hier ist eine Möglichkeit, dies zu tun:

#!/usr/bin/perl

use strict;
use warnings;

while ( <DATA> ) {
chomp;
last unless /S/;
my @fields = split;
if (
( my ($id, $name) = $fields[0] =~ /^([0-9]{3})([A-Za-z]{8,16})$/ )
and ( my ($phone) = $fields[1] =~ /^([0-9]{8})$/ )
) {
print "ID=$idnNAME=$namenPHONE=$phonen";
}
else {
warn "Invalid line: $_n";
}
}

__DATA__
123jackysee       45678887
456charliewong    32145644
678sdjkfhsdjhksadkjfhsdjjh 12345678

Und hier ist ein anderer Weg:

#!/usr/bin/perl

use strict;
use warnings;

while ( <DATA> ) {
chomp;
last unless /S/;
my ($id, $name, $phone) = unpack "A3A16A8";
if ( is_valid_id($id)
and is_valid_name($name)
and is_valid_phone($phone)
) {
print "ID=$idnNAME=$namenPHONE=$phonen";
}
else {
warn "Invalid line: $_n";
}
}

sub is_valid_id    { ($_[0]) = ($_[0] =~ /^([0-9]{3})$/) }

sub is_valid_name  { ($_[0]) = ($_[0] =~ /^([A-Za-z]{8,16})s*$/) }

sub is_valid_phone { ($_[0]) = ($_[0] =~ /^([0-9]{8})$/) }

__DATA__
123jackysee        45678887
456charliewong     32145644
678sdjkfhsdjhksadkjfhsdjjh 12345678

Verallgemeinerung:

#!/usr/bin/perl

use strict;
use warnings;

my %validators = (
id    => make_validator( qr/^([0-9]{3})$/ ),
name  => make_validator( qr/^([A-Za-z]{8,16})s*$/ ),
phone => make_validator( qr/^([0-9]{8})$/ ),
);

INPUT:
while ( <DATA> ) {
chomp;
last unless /S/;
my %fields;
@fields{qw(id name phone)} = unpack "A3A16A8";

for my $field ( keys %fields ) {
unless ( $validators{$field}->($fields{$field}) ) {
warn "Invalid line: $_n";
next INPUT;
}
}

print "$_ : $fields{$_}n" for qw(id name phone);
}

sub make_validator {
my ($re) = @_;
return sub { ($_[0]) = ($_[0] =~ $re) };
}

__DATA__
123jackysee        45678887
456charliewong     32145644
678sdjkfhsdjhksadkjfhsdjjh 12345678

0 für die Antwort № 7

Sie können Lookahead verwenden: ^(d{3})((?=[a-zA-Z]{8,})([a-zA-Z ]{16}))(d{8})$

Testen:

123jackysee 45678887Spiel 456charliewong 32145644 Match 789jop 12345678 Keine Übereinstimmung - Benutzername zu kurz 999abcdefghijabcde12345678 Keine Übereinstimmung - Benutzername "Spalte" ist weniger als 16 Zeichen 999abcdefghijabcdef12345678 Übereinstimmung 999abcdefghijabcdefg12345678 Keine Übereinstimmung - Benutzername Spalte mehr als 16 Zeichen