2009-05-15 15 views
20

Immaginate una stringa, come 'Agh # $% #% 2341- -! Zdrkfd' e desidero solo eseguire alcuni operatività in modo tale che vengano restituite solo le lettere minuscole (ad esempio), che in questo caso porterebbero 'ghzdrkfd'.Come si filtra una stringa in modo che vengano restituiti solo i caratteri nell'elenco?

Come si fa in Python? Il modo più ovvio sarebbe quello di creare una lista, di caratteri, da "a" a "z", quindi scorrere i caratteri nella mia stringa e creare una nuova stringa, carattere per carattere, solo per quelli della mia lista. Questo sembra primitivo.

Mi chiedevo se le espressioni regolari sono appropriate. Sostituire i caratteri indesiderati sembra problematico e io preferisco preferire la whitelist alla lista nera. La funzione .match non sembra appropriata. Ho esaminato la pagina appropriata sul sito Python, ma non ho trovato un metodo che sembra adattarsi.

Se le espressioni regolari non sono appropriate e l'approccio corretto è in loop, esiste una semplice funzione che "esplode" una stringa in una lista? O sto solo picchiando un altro per andare lì?

+0

http://stackoverflow.com/questions/89909/in-python-how-to-i-verify-that-a-string-only-contain-letters-numbers-underscor/ – Javier

risposta

4
s = 'ASDjifjASFJ7364' 
s_lowercase = ''.join(filter(lambda c: c.islower(), s)) 
print s_lowercase #print 'jifj' 
+3

Non è necessario chiamare lista su s. Gli oggetti stringa sono iterabili. –

17
s = 'Agh#$%#%2341- -!zdrkfd' 
print ''.join(c for c in s if c.islower()) 

oggetti String sono iterabili; non c'è bisogno di "esplodere" la stringa in una lista. Puoi inserire qualsiasi condizione tu voglia nella comprensione della lista e filtrerà i caratteri di conseguenza.

Si potrebbe anche implementare questo utilizzando una regex, ma questo nasconderà solo il ciclo. La libreria delle espressioni regolari dovrà ancora scorrere i caratteri della stringa per filtrarli.

+0

isalpha() non è necessario perché i caratteri non alfabetici restituiscono false su islower() –

+0

@coonj Good point. Fisso. –

+3

Questo può anche essere modificato per lavorare con un elenco di caratteri personalizzato cambiando 'c.islower()' ad es. 'c in" abcDEF "'. –

0

Vorrei usare un'espressione regolare. Per la corrispondenza minuscola [a-z].

4
>>> s = 'Agh#$%#%2341- -!zdrkfd' 
>>> ''.join(i for i in s if i in 'qwertyuiopasdfghjklzxcvbnm') 
'ghzdrkfd' 
5

Uso di un'espressione regolare è abbastanza facile, soprattutto per questo scenario:

>>> import re 
>>> s = 'ASDjifjASFJ7364' 
>>> re.sub(r'[^a-z]+', '', s) 
'jifj' 

Se avete intenzione di fare questo molte volte, è meglio per compilare l'espressione regolare prima di mano:

>>> import re 
>>> s = 'ASDjifjASFJ7364' 
>>> r = re.compile(r'[^a-z]+') 
>>> r.sub('', s) 
'jifj' 
+0

Per correttezza ho eseguito nuovamente il test sulla versione pre-compilata ed è ancora più lento di tradurre. –

+0

L'espressione regolare dovrebbe essere '[^ a-z] +' - questo migliora significativamente le prestazioni. – gnud

+0

@gnud, hai ragione sul miglioramento delle prestazioni. Ma è ancora molto più lento di tradurre. –

0
import string 
print "".join([c for c in "Agh#$%#%2341- -!zdrkfd" if c in string.lowercase]) 
30

Se siete alla ricerca di efficienza. L'uso della funzione translate è il più veloce che puoi ottenere.

Può essere utilizzato per sostituire rapidamente i caratteri e/o eliminarli.

import string 
delete_table = string.maketrans(
    string.ascii_lowercase, ' ' * len(string.ascii_lowercase) 
) 
table = string.maketrans('', '') 

"Agh#$%#%2341- -!zdrkfd".translate(table, delete_table) 

in Python 2.6: non occorre la seconda tabella più

import string 
delete_table = string.maketrans(
    string.ascii_lowercase, ' ' * len(string.ascii_lowercase) 
) 
"Agh#$%#%2341- -!zdrkfd".translate(None, delete_table) 

Questo è il metodo è il modo più veloce di qualsiasi altro. Ovviamente è necessario memorizzare delete_table da qualche parte e usarlo. Ma anche se non lo memorizzi e lo costruisci ogni volta, sarà comunque più veloce di altri metodi suggeriti finora.

Per confermare le mie affermazioni Ecco i risultati:

for i in xrange(10000): 
    ''.join(c for c in s if c.islower()) 

real 0m0.189s 
user 0m0.176s 
sys 0m0.012s 

Durante l'esecuzione la soluzione espressione regolare:

for i in xrange(10000): 
    re.sub(r'[^a-z]', '', s) 

real 0m0.172s 
user 0m0.164s 
sys 0m0.004s 

[Su richiesta] Se si pre-compilare l'espressione regolare:

r = re.compile(r'[^a-z]') 
for i in xrange(10000): 
    r.sub('', s) 

real 0m0.166s 
user 0m0.144s 
sys 0m0.008s 

Esecuzione del metodo di traduzione t egli stesso numero di volte ha preso:

real 0m0.075s 
user 0m0.064s 
sys 0m0.012s 
+2

Per essere onesti, è necessario compilare la regex all'esterno del ciclo. – Unknown

+0

Sto confrontando le migliori soluzioni suggerite. È così che Paolo Bergantino ha scritto la sua espressione. –

+0

L'ho scritto come una soluzione una tantum, sarebbe ovviamente meglio compilato, quindi dovresti confrontarlo come tale. –

1

Ecco un'unica soluzione se si è specificamente interessati a lavorare su stringhe:

s = 'Agh#$%#%2341- -!zdrkfd' 
lowercase_chars = [chr(i) for i in xrange(ord('a'), ord('z') + 1)] 
whitelist = set(lowercase_chars) 
filtered_list = [c for c in s if c in whitelist] 

La lista bianca è in realtà un insieme (non una lista) per l'efficienza.

Se avete bisogno di una stringa, utilizzare join():

filtered_str = ''.join(filtered_list) 

filtro() è una soluzione più generica. Dalla documentazione (http://docs.python.org/library/functions.html):

filtro (funzione, iterable)

Costruire un elenco da quegli elementi di iterable per i quali la funzione restituisce true. iterabile può essere una sequenza, un contenitore che supporta l'iterazione o un iteratore. Se iterable è una stringa o una tupla, il risultato ha anche quel tipo; altrimenti è sempre una lista. Se la funzione è None, si assume la funzione di identità, ovvero vengono rimossi tutti gli elementi iterabili che sono falsi.

Questo sarebbe un modo di utilizzare il filtro():

filtered_list = filter(lambda c: c.islower(), s) 
0
import string 

print filter(string.lowercase.__contains__, "lowerUPPER") 
print filter("123".__contains__, "a1b2c3") 
1

Una soluzione più generica e comprensibile per prendere un inputstring e filtrare contro un whitelist di caratteri:

inputstring = "Agh#$%#%2341- -!zdrkfd" 
whitelist = "abcdefghijklmnopqrstuvwxyz" 
remove = inputstring.translate(None, whitelist) 
result = inputstring.translate(None, remove) 
print result 

Questa stampa

ghzdrkfd 

Il primo string.translate rimuove tutti i caratteri nella whitelist dalla stringa di input. Questo ci dà i personaggi che vogliamo rimuovere. La seconda chiamata string.translate rimuove quelli dalla stringa di input e produce il risultato desiderato.

Problemi correlati