2013-02-27 14 views
5

Sto cercando di separare il [0-9] e [A-Z] nelle stringhe come questi:Come usare espressioni regolari per separare numeri e caratteri in stringhe come "30M1000N20M"

100M 
20M1D80M 
20M1I79M 
20M10000N80M 

Ho provato ad utilizzare il modulo Python re, e quello che segue è il codice che ho usato:

>>>import re 
>>>num_alpha = re.compile('(([0-9]+)([A-Z]))+') 
>>>str1="100M" 
>>>n_a_match = num_alpha.match(str1) 
>>>n_a_match.group(2), n_a_match.group(3) 

100,M #just what I want 

>>>str1="20M10000N80M" 
>>>n_a_match = num_alpha.match(str1) 
>>>n_a_match.groups() 

('80M', '80', 'M') #only the last one, how can I get the first two? 
#expected result ('20M','20','M','10000N','10000','N','80M','80','M') 

Questa espressione regolare funziona bene per le stringhe che contengono solo una partita, ma non diversi gruppi di partite. Come posso gestirlo usando le espressioni regolari?

risposta

3

Io suggerisco di usare re.findall. Se si intende iterare sui risultati, invece di creare un elenco, è possibile utilizzare invece re.finditer. Ecco un esempio di come dovrebbe funzionare:

>>> re.findall("(([0-9]+)([A-Z]))", "20M10000N80M") 
[('20M', '20', 'M'), ('10000N', '10000', 'N'), ('80M', '80', 'M')] 

Se non si desidera che la stringa di numeri + lettere combinato, è possibile rimuovere le parentesi esterne dal match e solo ottenere le parti separate:

>>> re.findall("([0-9]+)([A-Z])", "20M10000N80M") 
[('20', 'M'), ('10000', 'N'), ('80', 'M')] 

Oppure, se non vuoi affatto le tuple (e non devi preoccuparti dell'input non corretto, come stringhe con più lettere di fila), puoi cambiare il pattern in un'alternanza e ottenere i valori uno a uno:

>>> re.findall("([0-9]+|[A-Z])", "20M10000N80M") 
['20', 'M', '10000', 'N', '80', 'M'] 
+0

Grande. Non ho ricordato la funzione 'findall()'. Apprezza l'ultima espressione regolare. – ct586

+0

Tutte le risposte sono fantastiche. Se permesso, sceglierei tutti e tre. Ho scelto questo per la seconda espressione regolare dà esattamente quello che voglio. Ancora una volta, grazie a tutti. – ct586

3

provare a utilizzare il metodo di split:

>>> str1="20M10000N80M" 
>>> num_alpha = re.compile('(([0-9]+)([A-Z]))') 
>>> l = num_alpha.split(str1) 
>>> l 
['', '20M', '20', 'M', '', '10000N', '10000', 'N', '', '80M', '80', 'M', ''] 

Si noti che ho rimosso il + nel regex.

E per rimuovere le stringhe vuote, un generatore di lista:

>>> l_without_empty = [x for x in l if x != ''] 
['20M', '20', 'M', '10000N', '10000', 'N', '80M', '80', 'M'] 

Edit:

Oppure, come detto nei commenti:

>>> l_without_empty = [x for x in l if x] 
['20M', '20', 'M', '10000N', '10000', 'N', '80M', '80', 'M'] 
+2

Piccolo commento, è possibile utilizzare 'se non x' anziché' x! = '' '. Non è un problema, ma solo FYI – Serdalis

+0

Oh, bello! Grazie. – braunmagrin

+3

Aspetta, non è giusto. 'se non x' qui dovrebbe essere' se x'; vuoi mantenere quelli che hanno 'bool (x) == True'. 'se non x' manterrebbe solo quelli che * sono * vuoti. – DSM

2

Un'altra alternativa è di andare per re.findall invece:

>>> string = "20M10000N80M" 
>>> groups = re.findall(r'((\d+)(\D+))', string) 
[('20M', '20', 'M'), ('10000N', '10000', 'N'), ('80M', '80', 'M')] 

Quindi, è possibile vedere i diversi gruppi restituiti come tuple, allora, se si vuole veramente come una tupla come ti presenti - è possibile appiattirlo:

>>> from itertools import chain 
>>> tuple(chain.from_iterable(groups)) 
('20M', '20', 'M', '10000N', '10000', 'N', '80M', '80', 'M') 
+0

Grazie, molto bello. È mio piacere imparare il modulo "itertools". – ct586

+0

@ ct586 è una libreria molto utile e potente - divertiti nel tuo apprendimento! –

Problemi correlati