Wie kann ich alle Zeichen außer Zahlen aus der Zeichenfolge entfernen?
Wie kann ich alle Zeichen außer Zahlen aus der Zeichenfolge entfernen?
Antworten:
In Python 2. * ist der mit Abstand schnellste Ansatz die .translate
Methode:
>>> x='aaa12333bb445bb54b5b52'
>>> import string
>>> all=string.maketrans('','')
>>> nodigs=all.translate(all, string.digits)
>>> x.translate(all, nodigs)
'1233344554552'
>>>
string.maketrans
erstellt eine Übersetzungstabelle (eine Zeichenfolge mit der Länge 256), die in diesem Fall dieselbe ist wie ''.join(chr(x) for x in range(256))
(nur schneller zu erstellen ;-). .translate
wendet die Übersetzungstabelle an (die hier irrelevant ist, da sie im all
Wesentlichen Identität bedeutet) UND löscht Zeichen, die im zweiten Argument vorhanden sind - dem Schlüsselteil.
.translate
funktioniert sehr unterschiedlich auf Unicode - Strings (und Strings in Python 3 - ich tue Wunsch Fragen festgelegt , welche Hauptrelease von Python von Interesse ist!) - das nicht ganz einfach, das nicht ganz schnell, aber immer noch recht brauchbar.
Zurück zu 2. * ist der Leistungsunterschied beeindruckend ...:
$ python -mtimeit -s'import string; all=string.maketrans("", ""); nodig=all.translate(all, string.digits); x="aaa12333bb445bb54b5b52"' 'x.translate(all, nodig)'
1000000 loops, best of 3: 1.04 usec per loop
$ python -mtimeit -s'import re; x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'
100000 loops, best of 3: 7.9 usec per loop
Das 7-8-fache zu beschleunigen ist kaum Erdnuss, daher ist die translate
Methode es wert, sie zu kennen und anzuwenden. Der andere beliebte Nicht-RE-Ansatz ...:
$ python -mtimeit -s'x="aaa12333bb445bb54b5b52"' '"".join(i for i in x if i.isdigit())'
100000 loops, best of 3: 11.5 usec per loop
ist 50% langsamer als RE, daher .translate
schlägt der Ansatz ihn um mehr als eine Größenordnung.
In Python 3 oder für Unicode müssen Sie .translate
eine Zuordnung (mit Ordnungszahlen, nicht Zeichen direkt als Schlüssel) übergeben, die None
für das zurückgibt, was Sie löschen möchten. Hier ist eine bequeme Möglichkeit, dies auszudrücken, um "alles außer" ein paar Zeichen zu löschen:
import string
class Del:
def __init__(self, keep=string.digits):
self.comp = dict((ord(c),c) for c in keep)
def __getitem__(self, k):
return self.comp.get(k)
DD = Del()
x='aaa12333bb445bb54b5b52'
x.translate(DD)
emittiert auch '1233344554552'
. Wenn wir dies jedoch in xx.py einfügen, haben wir ...:
$ python3.1 -mtimeit -s'import re; x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'
100000 loops, best of 3: 8.43 usec per loop
$ python3.1 -mtimeit -s'import xx; x="aaa12333bb445bb54b5b52"' 'x.translate(xx.DD)'
10000 loops, best of 3: 24.3 usec per loop
... was zeigt, dass der Leistungsvorteil für diese Art von "Lösch" -Aufgaben verschwindet und zu einem Leistungsabfall wird.
x.translate(None, string.digits)
führt tatsächlich dazu 'aaabbbbbb'
, was das Gegenteil von dem ist, was beabsichtigt ist.
all
eingebautes ... da bin ich mir nicht sicher!
Verwenden Sie re.sub
wie folgt:
>>> import re
>>> re.sub('\D', '', 'aas30dsa20')
'3020'
\D
Entspricht einem nichtstelligen Zeichen, ersetzt der obige Code im Wesentlichen jedes nichtstellige Zeichen für die leere Zeichenfolge.
Oder Sie können filter
wie folgt verwenden (in Python 2):
>>> filter(str.isdigit, 'aas30dsa20')
'3020'
Da in Python 3 filter
ein Iterator anstelle von a zurückgegeben wird list
, können Sie stattdessen Folgendes verwenden:
>>> ''.join(filter(str.isdigit, 'aas30dsa20'))
'3020'
isdigit
, Generator mit isdigt
ist auf halbem Weg dazwischen
r
für rohe Saite verwenden:re.sub(r"\D+", "", "aas30dsa20")
s=''.join(i for i in s if i.isdigit())
Eine weitere Generatorvariante.
Sie können Filter verwenden:
filter(lambda x: x.isdigit(), "dasdasd2313dsa")
Auf python3.0 musst du dich dem anschließen (irgendwie hässlich :()
''.join(filter(lambda x: x.isdigit(), "dasdasd2313dsa"))
str
zu list
, um sicherzustellen, dass es sowohl auf py2 als auch auf py3 funktioniert:''.join(filter(lambda x: x.isdigit(), list("dasdasd2313dsa")))
in Anlehnung an Bayers Antwort:
''.join(i for i in s if i.isdigit())
-
es sich nicht um eine Ziffer handelt.
x.translate(None, string.digits)
löscht alle Ziffern aus der Zeichenfolge. Gehen Sie folgendermaßen vor, um Buchstaben zu löschen und die Ziffern beizubehalten:
x.translate(None, string.letters)
TypeError
: translate () nimmt genau ein Argument (2 angegeben). Warum diese Frage in ihrem gegenwärtigen Zustand positiv bewertet wurde, ist ziemlich frustrierend.
Die Op erwähnt in den Kommentaren, dass er die Dezimalstelle behalten möchte. Dies kann mit der Methode re.sub (gemäß der zweiten und meiner Meinung nach besten Antwort) erfolgen, indem die zu behaltenden Zeichen explizit aufgelistet werden, z
>>> re.sub("[^0123456789\.]","","poo123.4and5fish")
'123.45'
Eine schnelle Version für Python 3:
# xx3.py
from collections import defaultdict
import string
_NoneType = type(None)
def keeper(keep):
table = defaultdict(_NoneType)
table.update({ord(c): c for c in keep})
return table
digit_keeper = keeper(string.digits)
Hier ist ein Leistungsvergleich mit Regex:
$ python3.3 -mtimeit -s'import xx3; x="aaa12333bb445bb54b5b52"' 'x.translate(xx3.digit_keeper)'
1000000 loops, best of 3: 1.02 usec per loop
$ python3.3 -mtimeit -s'import re; r = re.compile(r"\D"); x="aaa12333bb445bb54b5b52"' 'r.sub("", x)'
100000 loops, best of 3: 3.43 usec per loop
Für mich ist es also etwas mehr als dreimal schneller als Regex. Es ist auch schneller als class Del
oben, da defaultdict
alle Suchvorgänge in C und nicht in (langsamem) Python ausgeführt werden. Hier ist diese Version auf meinem System zum Vergleich.
$ python3.3 -mtimeit -s'import xx; x="aaa12333bb445bb54b5b52"' 'x.translate(xx.DD)'
100000 loops, best of 3: 13.6 usec per loop
Hässlich aber funktioniert:
>>> s
'aaa12333bb445bb54b5b52'
>>> a = ''.join(filter(lambda x : x.isdigit(), s))
>>> a
'1233344554552'
>>>
list(s)
?
filter(lambda x: x.isdigit(), s)
hat gut für mich funktioniert. ... oh, das liegt daran, dass ich Python 2.7 verwende.
$ python -mtimeit -s'import re; x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'
100000 Schleifen, am besten 3: 2,48 usec pro Schleife
$ python -mtimeit -s'import re; x="aaa12333bab445bb54b5b52"' '"".join(re.findall("[a-z]+",x))'
100000 Schleifen, am besten 3: 2,02 usec pro Schleife
$ python -mtimeit -s'import re; x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'
100000 Schleifen, am besten 3: 2,37 usec pro Schleife
$ python -mtimeit -s'import re; x="aaa12333bab445bb54b5b52"' '"".join(re.findall("[a-z]+",x))'
100000 Schleifen, am besten 3: 1,97 usec pro Schleife
Ich hatte beobachtet, dass Join schneller als Sub ist.
Sie können jedes Zeichen lesen. Wenn es sich um eine Ziffer handelt, nehmen Sie sie in die Antwort auf. Mit dieser str.isdigit()
Methode können Sie feststellen, ob ein Zeichen eine Ziffer ist.
your_input = '12kjkh2nnk34l34'
your_output = ''.join(c for c in your_input if c.isdigit())
print(your_output) # '1223434'
Ich habe das benutzt. 'letters'
sollte alle Buchstaben enthalten, die Sie loswerden möchten:
Output = Input.translate({ord(i): None for i in 'letters'}))
Beispiel:
Input = "I would like 20 dollars for that suit"
Output = Input.translate({ord(i): None for i in 'abcdefghijklmnopqrstuvwxzy'}))
print(Output)
Ausgabe:
20