2014-02-11 15 views
6

Ich muss nur Zeichenfolgen herausfiltern, die nur Ziffern und/oder eine feste Satzzeichen enthalten.Filtern von Strings, die nur Ziffern und/oder Interpunktion enthalten - python

Ich habe versucht, jedes Zeichen zu überprüfen und dann die booleschen Bedingungen zu summieren, um zu überprüfen, ob es gleich len(str) ist. Gibt es einen pythonic Weg, dies zu tun:

>>> import string 
>>> x = ['12,523', '3.46', "this is not", "foo bar 42", "23fa"] 
>>> [i for i in x if [True if j.isdigit() else False for j in i] ] 
['12,523', '3.46', 'this is not', 'foo bar 42'] 
>>> [i for i in x if sum([True if j.isdigit() or j in string.punctuation else False for j in i]) == len(i)] 
['12,523', '3.46'] 
+0

Sind Sie sicher, dass Sie nicht ** wirklich ** meinen "Ich muss Strings finden, die Zahlen darstellen könnten, aber' float' usw. funktioniert nicht, weil ich auch Kommas als Tausendertrennzeichen zulassen möchte "? –

+0

Ja, ich brauche das später, aber eine zweischichtige Filterung wird auch numerische Indexierung in legalen Dokumenten erfassen (zB 'x = [" chapter "," 1.2.3.5 "]') – alvas

Antwort

4

Mit all mit Generator Ausdruck, die Sie nicht zählen müssen, zu vergleichen, Länge:

>>> [i for i in x if all(j.isdigit() or j in string.punctuation for j in i)] 
['12,523', '3.46'] 

BTW, oben und Code des OP gehört Strings Das enthält nur Interpunktionen.

>>> x = [',,,', '...', '123', 'not number'] 
>>> [i for i in x if all(j.isdigit() or j in string.punctuation for j in i)] 
[',,,', '...', '123'] 

Um das zu umgehen, mehr Bedingung hinzu:

>>> [i for i in x if all(j.isdigit() or j in string.punctuation for j in i) and any(j.isdigit() for j in i)] 
['123'] 

Sie es durch Speichern des Ergebnisses von string.punctuation in einem Satz ein wenig schneller machen kann.

+0

Sie könnten es vielleicht ein bisschen schneller machen, indem Sie speichern das Ergebnis von 'string.punctuation' in einem' set'. –

+0

@ FrerichRaabe, Danke für den Kommentar. Ich habe deinen Kommentar hinzugefügt. – falsetru

3

Sie können einen vorkompilierten regulären Ausdruck verwenden, um dies zu überprüfen.

import re, string 
pattern = re.compile("[\d{}]+$".format(re.escape(string.punctuation))) 
x = ['12,523', '3.46', "this is not", "foo bar 42", "23fa"] 
print [item for item in x if pattern.match(item)] 

Ausgabe

['12,523', '3.46'] 

Ein wenig Timing Vergleich zwischen @ falsetru-Lösung und meinem

import re, string 
punct = string.punctuation 
pattern = re.compile("[\d{}]+$".format(re.escape(string.punctuation))) 
x = ['12,523', '3.46', "this is not", "foo bar 42", "23fa"] 

from timeit import timeit 
print timeit("[item for item in x if pattern.match(item)]", "from __main__ import pattern, x") 
print timeit("[i for i in x if all(j.isdigit() or j in punct for j in i)]", "from __main__ import x, punct") 

Ausgang auf meinem Rechner

2.03506183624 
4.28856396675 

Der vorkompilierte RegEx-Ansatz ist also doppelt so schnell wie der all- und any-Ansatz.