Regex: abbina una stringa contenente numeri e lettere ma non una stringa di soli numeri
-
11-09-2019 - |
Domanda
Domanda
Vorrei poter usare un singolo regex (se possibile) per richiedere che una stringa si adatti [A-Za-z0-9_]
Ma non permette:
- Stringhe contenenti solo numeri o/e simboli.
- Stringhe che iniziano o finiscono con simboli
- Più simboli accanto all'altro
Valido
test_0123
t0e1s2t3
0123_test
te0_s1t23
t_t
Non valido
t__t
____
01230123
_0123
_test
_test123
test_
test123_
Motivi per le regole
Lo scopo è di filtrare i nomi utente per un sito web su cui sto lavorando. Sono arrivato alle regole per motivi specifici.
I nomi utente con solo numeri e/o simboli potrebbero causare problemi con le ricerche di routing e database. Il percorso per
/users/#{id}
consenteid
Per essere l'ID dell'utente o il nome dell'utente. Quindi i nomi e gli ID non dovrebbero essere in grado di scontrarsi._test
sembra strano e non credo che sia valido sottodominio cioè_test.example.com
Non mi piace l'aspetto di
t__t
come sottodominio. cioèt__t.example.com
Soluzione
Questo corrisponde esattamente quello che vuoi:
/\A(?!_)(?:[a-z0-9]_?)*[a-z](?:_?[a-z0-9])*(?<!_)\z/i
- Almeno un carattere alfabetico (il
[a-z]
nel mezzo). - Non inizia o termina con un sottoline (il
(?!_)
e(?<!_)
all'inizio e alla fine). - Può avere un numero qualsiasi di numeri, lettere o sottotizzato prima e dopo il carattere alfabetico, ma ogni sottolineatura deve essere separato da almeno un numero o lettera (il resto).
EDIT: In effetti, probabilmente non hai nemmeno bisogno di lookahead/lookbehinds a causa di come funziona il resto del regex - il primo ?:
parentetico non permetterà a un sottolineato fino a dopo un alfanumerico e il secondo ?:
Parenteretico non permetterà a un sottolineaggio a meno che non sia davanti a un alfanumerico:
/\A(?:[a-z0-9]_?)*[a-z](?:_?[a-z0-9])*\z/i
Dovrebbe funzionare bene.
Altri suggerimenti
Sono sicuro che tu Potevo Metti tutto questo in un'unica espressione regolare, ma non sarà semplice e non sono sicuro del perché insistere sull'essere uno Regex. Perché non utilizzare più passaggi durante la convalida? Se i controlli di convalida vengono eseguiti quando gli utenti creano un nuovo account, non c'è davvero motivo per provare a stiparlo in un unico regex. (Cioè, avrai a che fare con un solo elemento alla volta, non centinaia o migliaia o più. Alcuni passaggi su un nome utente di dimensioni normali dovrebbero richiedere pochissimo tempo, penso.)
Per prima cosa rifiuta se il nome non contiene almeno un numero; Quindi rifiuta se il nome non contiene almeno una lettera; Quindi controlla che l'inizio e la fine siano corretti; ecc. Ognuno di questi passaggi potrebbe essere un semplice da leggere e facile da mantenere un'espressione regolare.
Che dire:
/^(?=[^_])([A-Za-z0-9]+_?)*[A-Za-z](_?[A-Za-z0-9]+)*$/
Non usa un riferimento posteriore.
Modificare:
Riesce a tutti i tuoi casi di test. È compatibile con Ruby.
Questo non blocca "__", ma ottiene il resto:
([A-Za-z]|[0-9][0-9_]*)([A-Za-z0-9]|_[A-Za-z0-9])*
Ed ecco la forma più lunga che ottiene tutte le tue regole:
([A-Za-z]|([0-9]+(_[0-9]+)*([A-Za-z|_[A-Za-z])))([A-Za-z0-9]|_[A-Za-z0-9])*
Dang, è brutto. Sarò d'accordo con Telemaco, che probabilmente non dovresti farlo con un regex, anche se è tecnicamente possibile. Regex è spesso un dolore per la manutenzione.
La domanda pone un singolo regexp e implica che dovrebbe essere un regexp che corrispondenze, che va bene e ha risposto dagli altri. Per interesse, tuttavia, noto che queste regole sono piuttosto più facili da dichiarare direttamente come un regexp che dovrebbe non incontro. Cioè:
x !~ /[^A-Za-z0-9_]|^_|_$|__|^\d+$/
- nessun altro personaggio di lettere, numeri e _
- Non posso iniziare con un _
- non posso finire con un _
- Non posso avere due _s di fila
- Non può essere tutte le cifre
Non puoi usarlo in questo modo in un galls validates_format_of, ma potresti metterlo in un metodo di validato per la classe, e penso che avresti molto più possibilità di essere ancora in grado di dare un senso a ciò che intendevi, un mese o tra un anno.
Ecco qui:
^(([a-zA-Z]([^a-zA-Z0-9]?[a-zA-Z0-9])*)|([0-9]([^a-zA-Z0-9]?[a-zA-Z0-9])*[a-zA-Z]+([^a-zA-Z0-9]?[a-zA-Z0-9])*))$
Se vuoi limitare i simboli che desideri accettare, modifica semplicemente tutti [^a-za-z0-9] con [] contenente tutti i simboli consentiti
(?=.*[a-zA-Z].*)^[A-Za-z0-9](_?[A-Za-z0-9]+)*$
Questo funziona.
Guarda avanti per assicurarti che ci sia almeno una lettera nella stringa, quindi inizia a consumare input. Ogni volta che c'è un sottolineaggio, ci deve essere un numero o una lettera prima del prossimo sottolineaggio.
/^(?![\d_]+$)[A-Za-z0-9]+(?:_[A-Za-z0-9]+)*$/
La tua domanda è essenzialmente la stessa Questo, con il requisito aggiunto secondo cui almeno uno dei personaggi deve essere una lettera. Il lookahead negativo - (?![\d_]+$)
- Si prende cura di quella parte ed è molto più facile (sia leggere e scrivere) che incorporarlo nel regex di base come alcuni altri hanno cercato di fare.
[A-Za-z][A-Za-z0-9_]*[A-Za-z]
Funzionerebbe per le tue prime due regole (poiché richiede una lettera all'inizio e alla fine per la seconda regola, richiede automaticamente lettere).
Non sono sicuro che la terza regola sia possibile usando i regex.