/ / Regex per controllare il campo della lunghezza della correzione con lo spazio imballato - regex

Regex per controllare il campo della lunghezza fissa con spazio occupato - regex

Supponiamo che io abbia un file di testo da analizzare, che contiene alcuni contenuti a lunghezza fissa:

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

I primi tre caratteri sono ID, quindi nome utente di 16 caratteri, quindi numero di telefono di 8 cifre.

Vorrei scrivere un'espressione regolare per abbinare e verificare l'input per ogni riga, quella che mi viene in mente:

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

Il nome utente dovrebbe contenere 8-16 caratteri. Ma ([A-Za-z ]{16}) corrisponderebbe anche a un valore o uno spazio nulli. penso a ([A-Za-z]{8,16} {0,8}) ma rileverà più di 16 caratteri. Eventuali suggerimenti?

risposte:

7 per risposta № 1

No, no, no, no! :-)

Perché le persone insistono nel cercare di racchiudere così tante funzionalità in una singola istruzione RE o SQL?

Il mio suggerimento, fai qualcosa come:

  • Assicurati che la lunghezza sia 27.
  • Estrai i tre componenti in stringhe separate (0-2, 3-18, 19-26).
  • Controlla che le prime corrispondano "d{3}".
  • Controlla che il secondo corrisponda "[A-Za-z]{8,} *".
  • Controlla che il terzo corrisponda "d{8}".

Se vuoi che l'intero controllo si adatti a una riga di codice sorgente, inseriscilo in una funzione, isValidLine()e chiamalo.

Anche qualcosa di simile farebbe il trucco:

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

Non fatevi ingannare pensando che sia Python pulitocode, in realtà è PaxLang, il mio pseudo-codice proprietario. Si spera che sia abbastanza chiaro, la prima riga controlla che la lunghezza sia 27, la seconda che corrisponda alla data RE.

Il campo centrale contiene automaticamente 16 caratteritotale dovuto alla prima riga e al fatto che gli altri due campi sono di lunghezza fissa nella RE. La RE assicura anche che siano otto o più alfa seguiti dal giusto numero di spazi.

Fare questo genere di cose con una singola RE sarebbe una mostruosità come:

^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}$

Puoi farlo assicurandoti che ne superi due separato RE:

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

ma, poiché quest'ultimo è semplicemente un controllo della lunghezza, non è diverso dal isValidLine() sopra.


0 per risposta № 2

Userei la regex che hai suggerito con una piccola aggiunta:

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

che corrisponderà alle cose che hanno unnome utente diverso da spazi ma consente comunque il riempimento dello spazio. L'unica aggiunta è che dovresti controllare la lunghezza di ogni input per verificare il numero corretto di caratteri.


0 per risposta № 3

Hmm ... A seconda della versione esatta di Regex che stai utilizzando, considera:

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

Nota che è sicuro al 100% che funzionerà, e ho usato il carattere di escape dello spazio bianco invece di uno spazio reale - mi innervosisco solo con il carattere spazio io stesso, ma potresti voler essere più restrittivo.

Vedi se funziona. Sono solo intermedio con RegEx, quindi potrei essere in errore.

Controlla la sintassi dei gruppi denominati per la tua versione di RegEx a) esiste eb) corrisponde allo standard che ho usato sopra.

MODIFICARE:

Solo per espandere quello che sto cercando di fare (mi dispiace farti sanguinare gli occhi, Pax!) Per coloro che non hanno molta esperienza con le RegEx:

(?P<id>d{3})

Questo proverà a far corrispondere un gruppo di cattura con nome -"id" - ovvero tre cifre di lunghezza. La maggior parte delle versioni di RegEx ti consente di utilizzare gruppi di acquisizione con nome per estrarre i valori con cui hai confrontato. Ciò consente di eseguire la convalida e l'acquisizione dei dati allo stesso tempo. Diverse versioni di RegEx hanno sintassi leggermente diverse per questo - controlla http://www.regular-expressions.info/named.html per maggiori dettagli sulla tua particolare implementazione.

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

? = È un operatore di lookahead.Questo guarda avanti per i successivi sedici caratteri e restituirà vero se sono tutte lettere o caratteri di spazio e sono seguiti da una cifra. L'operatore lookahead è di lunghezza zero, quindi in realtà non restituisce nulla. La stringa RegEx continua dal punto in cui è iniziato Lookahead. Controlla http://www.regular-expressions.info/lookaround.html per maggiori dettagli su lookahead.

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

Se il lookahead passa, continuiamo a contaredal quarto carattere in. Vogliamo trovare da otto a sedici caratteri, seguiti da zero o più spazi bianchi. Il "o più" è effettivamente sicuro, poiché "abbiamo già verificato nel lookahead" che non possono esserci più di sedici caratteri in totale prima della cifra successiva.

Finalmente,

(?P<phone>d{8})

Questo dovrebbe controllare il numero di telefono a otto cifre.

Sono un po 'nervoso che questo non funzioni esattamente - la tua versione di RegEx potrebbe non supportare la sintassi del gruppo denominato o la sintassi lookahead a cui sono abituato.

Sono anche un po 'nervoso che questo Regex corrisponda con successo a una stringa vuota. Diverse versioni di Regex gestiscono le stringhe vuote in modo diverso.

Potresti anche prendere in considerazione l'ancoraggio di questo Regex tra a ^ e $ per assicurarti di "far corrispondere l'intera linea, e non solo una parte di una linea più grande.


0 per risposta № 4

Supponendo che tu intenda perl regex e se consenti "_" nel nome utente:

perl -ne "uscita 1 a meno che / (d {3}) (w {8,16}) s + (d {8}) / && length == 28"

0 per risposta № 5

@ OP, non tutti i problemi richiedono una regex.il tuo problema è abbastanza semplice da controllare. a seconda della lingua che stai usando, avrebbero una sorta di funzioni stringa incorporate. usali. il seguente esempio minimo è fatto in Python.

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 per risposta № 6

Inoltre, non credo che dovresti provare a raggruppare tutte le funzionalità in un'unica espressione regolare. Ecco un modo per farlo:

#!/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

Ed ecco un altro modo:

#!/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

Generalizzare:

#!/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 per risposta № 7

Puoi usare lookahead: ^(d{3})((?=[a-zA-Z]{8,})([a-zA-Z ]{16}))(d{8})$

test:

123jackysee 45678887Incontro 456charliewong 32145644 Partita 789jop 12345678 Nessuna corrispondenza: nome utente troppo corto 999abcdefghijabcde12345678 Nessuna corrispondenza: il nome utente "colonna" contiene meno di 16 caratteri 999abcdefghijabcdef12345678 Partita 999abcdefghijabcdefg12345678 Nessuna corrispondenza - colonna nome utente con più di 16 caratteri