def format_title(title):
''.join(map(lambda x: x if (x.isupper() or x.islower()) else '_', title.strip()))
Alles schneller?Python - effiziente Methode, um alle Nicht-Buchstaben zu entfernen und durch Unterstriche zu ersetzen
def format_title(title):
''.join(map(lambda x: x if (x.isupper() or x.islower()) else '_', title.strip()))
Alles schneller?Python - effiziente Methode, um alle Nicht-Buchstaben zu entfernen und durch Unterstriche zu ersetzen
Je schneller Weg, es zu tun ist, str.translate()
zu verwenden Dies ist ~ 50-mal schneller als die Art und Weise ist
# You only need to do this once
>>> title_trans=''.join(chr(c) if chr(c).isupper() or chr(c).islower() else '_' for c in range(256))
>>> "[email protected]%^".translate(title_trans)
'abcde________'
# Using map+lambda
$ python -m timeit '"".join(map(lambda x: x if (x.isupper() or x.islower()) else "_", "[email protected]#$".strip()))'
10000 loops, best of 3: 21.9 usec per loop
# Using str.translate
$ python -m timeit -s 'titletrans="".join(chr(c) if chr(c).isupper() or chr(c).islower() else "_" for c in range(256))' '"[email protected]#$".translate(titletrans)'
1000000 loops, best of 3: 0.422 usec per loop
# Here is regex for a comparison
$ python -m timeit -s 'import re;transre=re.compile("[\W\d]+")' 'transre.sub("_","[email protected]#$")'
100000 loops, best of 3: 3.17 usec per loop
Hier eine Version für Unicode
# coding: UTF-8
def format_title_unicode_translate(title):
return title.translate(title_unicode_trans)
class TitleUnicodeTranslate(dict):
def __missing__(self,item):
uni = unichr(item)
res = u"_"
if uni.isupper() or uni.islower():
res = uni
self[item] = res
return res
title_unicode_trans=TitleUnicodeTranslate()
print format_title_unicode_translate(u"Metallica Μεταλλικα")
Beachten Sie, dass die griechischen Buchstaben zählen als obere und untere, also sind sie nicht substituiert. Wenn sie substituiert sind, einfach die Bedingung
if item<256 and (uni.isupper() or uni.islower()):
import re
title = re.sub("[\W\d]", "_", title.strip())
sollte schneller sein.
Wenn Sie eine Reihe von benachbarten, nicht-Buchstaben mit einem Unterstrich zu ersetzen, verwenden
title = re.sub("[\W\d]+", "_", title.strip())
statt, die noch schneller ist.
Ich lief einen Zeitvergleich:.
C:\>python -m timeit -n 100 -s "data=open('test.txt').read().strip()" "''.join(map(lambda x: x if (x.isupper() or x.islower()) else '_', data))"
100 loops, best of 3: 4.51 msec per loop
C:\>python -m timeit -n 100 -s "import re; regex=re.compile('[\W\d]+'); data=open('test.txt').read().strip()" "title=regex.sub('_',data)"
100 loops, best of 3: 2.35 msec per loop
Dies wird auf Unicode-Strings arbeiten, auch (unter Python 3, \W
jedes Zeichen, das keine Unicode Wortzeichen ist unter 2 Python, würden Sie muss hierfür zusätzlich die UNICODE
Flag setzen.
Die Art und Weise Sie timeit verwenden ist die ganze Zeit zu zählen, die Datei zu öffnen und zu lesen.Sie sollten dieses Zeug in den '-s' Teil verschieben, um aussagekräftige Ergebnisse zu erhalten. –
Danke, Sie haben natürlich Recht. Da dies in beiden Beispielen gemacht wurde, sollte der Fehler in beiden Fällen gleich sein (und ist, ich habe es gerade versucht). Interessanterweise fand ich, dass das Vorkompilieren der Regex keinen Unterschied machte. Ich habe die Timing-Beispiele trotzdem aktualisiert. –
Beachten Sie, dass Sie Flags mit re nicht setzen können; Sie müssen re.compile() verwenden, um Flags anzugeben und sub() für das Ergebnis aufzurufen. (Dies ist eine merkwürdige API-Auslassung.) Ihre Antwort wäre besser mit der "+" Version entfernt; Es ist nicht das, wonach er gefragt hat, also ist es nur ablenkend. –
ändern Statt (x.isupper() or x.islower())
Sie sollten in der Lage sein x.isalpha()
zu verwenden. Die isalpha()
Methode kann True
für '_'
zurückgeben (ich erinnere mich nicht, wenn es tut oder nicht), aber dann werden Sie nur '_'
mit '_'
ersetzen, so dass kein Schaden angerichtet wird. (Danke dafür, dass Sie darauf hingewiesen haben, KennyTM.)
Eigentlich könnte es '_' selbst als '_' zählen alphabetischer Charakter, also vielleicht nicht. Probieren Sie es aus und sehen Sie. – MatrixFrog
Das Ersetzen von '_' durch' _' (oder nicht) ist harmlos. – kennytm
Neugierig aus meinen eigenen Gründen schrieb ich ein schnelles Skript, um die verschiedenen hier aufgeführten Ansätze zu testen und nur das Lambda zu entfernen, von dem ich erwartete (fälschlicherweise) würde das Original beschleunigen Lösung.
Die kurze Version ist, dass der str.translate Ansatz die anderen wegbläst. Nebenbei bemerkt ist die Regex-Lösung, obwohl sie nahe beieinander ist, korrekt, wie oben beschrieben.
Hier Programm mein Test ist:
import re
from time import time
def format_title(title):
return ''.join(map(lambda x: x if (x.isupper() or x.islower()) else "_",
title.strip()))
def format_title_list_comp(title):
return ''.join([x if x.isupper() or x.islower() else "_" for x in
title.strip()])
def format_title_list_comp_is_alpha(title):
return ''.join([x if x.isalpha() else "_" for x in title.strip()])
def format_title_is_alpha(title):
return ''.join(map(lambda x: x if x.isalpha() else '_', title.strip()))
def format_title_no_lambda(title):
def trans(c):
if c.isupper() or c.islower():
return c
return "_"
return ''.join(map(trans, title.strip()))
def format_title_no_lambda_is_alpha(title):
def trans(c):
if c.isalpha():
return c
return "_"
return ''.join(map(trans, title.strip()))
def format_title_re(title):
return re.sub("[\W\d]+", "_", title.strip())
def format_title_re_corrected(title):
return re.sub("[\W\d]", "_", title.strip())
TITLE_TRANS = ''.join(chr(c) if chr(c).isalpha() else '_' for c in range(256))
def format_title_with_translate(title):
return title.translate(TITLE_TRANS)
ITERATIONS = 200000
EXAMPLE_TITLE = "abc123def_$%^!FOO BAR*bazx-bif"
def timetest(f):
start = time()
for i in xrange(ITERATIONS):
result = f(EXAMPLE_TITLE)
diff = time() - start
return result, diff
baseline_result, baseline_time = timetest(format_title)
def print_result(f, result, time):
if result == baseline_result:
msg = "CORRECT"
else:
msg = "INCORRECT"
diff = time - baseline_time
if diff < 0:
indicator = ""
else:
indicator = "+"
pct = (diff/baseline_time) * 100
print "%s: %0.3fs %s%0.3fs [%s%0.4f%%] (%s - %s)" % (
f.__name__, time, indicator, diff, indicator, pct, result, msg)
print_result(format_title, baseline_result, baseline_time)
print "----"
for f in [format_title_is_alpha,
format_title_list_comp,
format_title_list_comp_is_alpha,
format_title_no_lambda,
format_title_no_lambda_is_alpha,
format_title_re,
format_title_re_corrected,
format_title_with_translate]:
alt_result, alt_time = timetest(f)
print_result(f, alt_result, alt_time)
Und hier sind die Ergebnisse:
format_title: 3.121s +0.000s [+0.0000%] (abc___def_____FOO_BAR_bazx_bif - CORRECT)
----
format_title_is_alpha: 2.336s -0.785s [-25.1470%] (abc___def_____FOO_BAR_bazx_bif - CORRECT)
format_title_list_comp: 2.369s -0.751s [-24.0773%] (abc___def_____FOO_BAR_bazx_bif - CORRECT)
format_title_list_comp_is_alpha: 1.735s -1.386s [-44.4021%] (abc___def_____FOO_BAR_bazx_bif - CORRECT)
format_title_no_lambda: 2.992s -0.129s [-4.1336%] (abc___def_____FOO_BAR_bazx_bif - CORRECT)
format_title_no_lambda_is_alpha: 2.377s -0.744s [-23.8314%] (abc___def_____FOO_BAR_bazx_bif - CORRECT)
format_title_re: 1.290s -1.831s [-58.6628%] (abc_def__FOO_BAR_bazx_bif - INCORRECT)
format_title_re_corrected: 1.338s -1.782s [-57.1165%] (abc___def_____FOO_BAR_bazx_bif - CORRECT)
format_title_with_translate: 0.098s -3.022s [-96.8447%] (abc___def_____FOO_BAR_bazx_bif - CORRECT)
Die Regex-Lösung ist falsch, da sie mehrere benachbarte Nicht-Buchstaben als nur einen Unterstrich ersetzt. Lege das '+' nach der Zeichenklasse ab und es wird korrekt sein, wenn auch langsamer. Ich denke, die Frage ist, ob Sie wirklich lange Unterstreichungsstriche in Ihren Ersatzsträngen haben wollen oder nicht ... –
import string,sys
letters=string.letters
mystring = list("abc134#[email protected]##$%%$*&(()#def")
for n,c in enumerate(mystring):
if not c in letters:
mystring[n]="_"
print ''.join(mystring)
+1, sehr gute Idee. Der einzige Nachteil, den ich mir vorstellen kann, ist, dass dies bei Unicode-Zeichenfolgen nicht richtig funktioniert, wenn Nicht-ASCII-Zeichen berücksichtigt werden müssen. –
@Tim, Unicode hat auch einen übersetzen - die Semantik ist anders, lass mich sehen, ob ich es zur Arbeit bekommen kann ... –
@Tim, Unicode-Version ist up. Das Übersetzungsmapping wird auf Anfrage erstellt und wird daher immer weniger Fehler haben, wenn mehr Strings übersetzt werden. –