2011-03-08 14 views
9

Ho un'espressione regolare piuttosto lunga per abbinare una voce in una lista che sto elaborando. L'elenco dovrebbe essere una o più di queste voci, separate da virgola. Si consideri un'espressione regolare:Ripetizioni separate da virgola

([abc]+|[123]+) 

per la voce. Per abbinare il mio elenco separato da virgole, sto corrispondenza con qualcosa di simile:

([abc]+|[123]+)(,([abc]+|[123]+))* 

(E sembra particolarmente insensato con la mia brutta regex invece di quello corto che ho usato qui per l'esempio)

I senti che ci deve essere un modo migliore di avere due copie della voce - una volta per la prima, ancora per e seguire le coppie di comma/entrata.

risposta

3

Qualcosa di simile, forse:

((?!=^|,)([abc123]))+ 

ruppe è:

(      # start of parent capture 
    (?!=^|,)    # look ahead and find either the start of a line or a comma 
    ([abc123])    # actual pattern to look for (token) 
)+      # say this whole pattern is repeatable 

PHP Demo (Era più semplice modo per dimostrare)

+0

Non penso che tu voglia il '!' Nel tuo sguardo avanti (che è per uno sguardo negativo avanti), ma uno sguardo al futuro non corrisponde effettivamente a un personaggio, quindi questo non corrisponderà. Dovresti stare bene senza guardare in avanti '(?: (?:^|,) ([A-c1-3])) +' – jswolf19

+0

@ jswolf19: Lo uso per evitare che il personaggio finisca nella partita. Immagino preferenza personale. - La combinazione mi dà anche la prima partita e il resto. (senza di esso o otterrò solo il primo token, o il 2 ° in poi) –

+0

So che non vuoi il "," nella partita, ma deve essere abbinato: se hai 'a, 1', allora la tua regex non corrisponderà. il lookahead vede il ',', ma è ancora lì quando si tenta di abbinare il 1 perché il lookahead non getta il ',' via. Hai bisogno di un gruppo non catturante per quello '(?:)'. – jswolf19

6

Sembra che si desidera backreferences.

([abc123])(,\1)* 

Inoltre, appena cronaca, [abc]|[123] è equivalente a [abc123].


Edit: base alla tua modifica, penso che ho frainteso quello che stavi cercando di fare. Prova questo:

([abc123]+(,|$))* 

Oppure, se si vuole essere meno restrittivo:

([^,]+(,|$))* 

Questo corrisponde stringhe di caratteri non-virgola separati da virgole. Un approccio più semplice sarebbe solo una corrispondenza globale per [^,]+ di per sé. In JavaScript, che sarebbe simile a questa:

myString.match(/[^,]+/g) //or /[abc123]+/g, or whatever 

Oppure si può semplicemente dividere il virgole:

myString.split(/,/) 
+0

che dirà che il prossimo token deve essere lo stesso del precedente, non che deve adattarsi allo schema. (non sono sicuro che sia ciò che l'OP vuole, sono solo curiosi di sapere se devono specificare il modello due volte [potrei sbagliarmi ...]) –

+0

@Brad: non è questo quello che sta facendo? Forse sono confuso. –

+0

@JustinEMorgan: Forse hai ragione. L'ho letto come "devo specificare il modello da cercare due volte?" E "altrimenti, come evito di farlo". –

0

Nel mio caso sto testando l'intera linea.

/(?!^,)^((^|,)([abc]+|[123]+))+$/.test('a,b,c,1,2,3'); 
true 

Il lookahead negativo esclude una virgola iniziale.

/(?!^,)^((^|,)([abc]+|[123]+))+$/.test(',a,b,c,1,2,3'); 
false 

Se sono necessari i singoli componenti effettuare una divisione semplice dopo la convalida.

Sto convalidando sezioni e sottosezioni suddivise in PLSS.

// Check for one or more Section Specs consisting of an optional 
// subsection followed by an "S" and one or two digits. Multiple 
// Section Specs are separated by space or a comma and optional space. 
// 
// Example: SW/4 SW/4 S1, E/2 S2, N/2 N/2 S12 
// 
// Valid subsections are - 
// (1) [NS][EW]/4\s+[NS][EW]/4 eg. NW/4 SE/4 (40 ac) 
// (2) [NSEW]/2\s+[NS][EW]/4  eg. N/2 SE/4 (80 ac) 
// (3) [NS]/2\s+[NS]/2   eg. N/2 S/2 (160 ac) 
// (4) [EW]/2\s+[EW]/2   eg. E/2 W/2 (160 ac) 
// (5) [NS][EW]/4    eg. NE/4 (160 ac) 
// (6) [NSEW]/2     eg. E/2 (320 ac) 
// (7) 1/1      Shorthand for the full section (640 ac) 
// 
// Expressions like E/2 N/2 are not valid. Use NE/4 instead. 
// Expressions like NW/4 E/2 are not valid. You probably want W/2 NE/4. 

var pat = '' + 
    '(([NS][EW]/4|[NSEW]/2)\\s+)?[NS][EW]/4\\s+' + // (1), (2) & (5) 
    '|([NS]/2\\s+)?[NS]/2\\s+' +      // (3) & part of (6) 
    '|([EW]/2\\s+)?[EW]/2\\s+' +      // (4) & part of (6) 
    '|1/1\\s+';          // (7) 

pat = '(' + pat + ')?' + 'S\\d{1,2}';     // a Section Spec 

// Line anchors, join alternatives and negative lookahead to exclude an initial comma 
pat = '(?!^,)^((^|,\\s*|\\s+)(' + pat + '))+$'; 

var re = new RegExp(pat, 'i'); 

console.log(pat); 
(?!^,)^((^|,\s*|\s+)(((([NS][EW]/4|[NSEW]/2)\s+)?[NS][EW]/4\s+|([NS]/2\s+)?[NS]/2\s+|([EW]/2\s+)?[EW]/2\s+|1/1\s+)?S\d{1,2}))+$ 

Una volta convalidato, ho diviso utilizzando un lookbehind positivo.

Problemi correlati