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} consente id 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

È stato utile?

Soluzione

Questo corrisponde esattamente quello che vuoi:

/\A(?!_)(?:[a-z0-9]_?)*[a-z](?:_?[a-z0-9])*(?<!_)\z/i
  1. Almeno un carattere alfabetico (il [a-z] nel mezzo).
  2. Non inizia o termina con un sottoline (il (?!_) e (?<!_) all'inizio e alla fine).
  3. 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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top