def format_title(title):
''.join(map(lambda x: x if (x.isupper() or x.islower()) else '_', title.strip()))
Mọi thứ nhanh hơn?Python - phương pháp hiệu quả để xóa tất cả các chữ cái và thay thế chúng bằng dấu gạch dưới
def format_title(title):
''.join(map(lambda x: x if (x.isupper() or x.islower()) else '_', title.strip()))
Mọi thứ nhanh hơn?Python - phương pháp hiệu quả để xóa tất cả các chữ cái và thay thế chúng bằng dấu gạch dưới
Cách nhanh hơn để làm điều đó là sử dụng str.translate()
Đây là ~ nhanh hơn 50 lần so với cách của bạn
# 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
Dưới đây là một phiên bản dành cho 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 Μεταλλικα")
Lưu ý rằng các chữ cái Hy Lạp đếm như trên và dưới, vì vậy chúng không được thay thế. Nếu chúng được thay thế, chỉ cần thay đổi điều kiện để
if item<256 and (uni.isupper() or uni.islower()):
import re
title = re.sub("[\W\d]", "_", title.strip())
sẽ nhanh hơn.
Nếu bạn muốn thay thế một chuỗi các liền kề phi thư với một dấu gạch dưới duy nhất, sử dụng
title = re.sub("[\W\d]+", "_", title.strip())
thay vì đó thậm chí còn nhanh hơn.
Tôi chỉ cần chạy một so sánh thời gian:.
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
này sẽ làm việc trên chuỗi Unicode, quá (dưới Python 3, \W
trận đấu bất kỳ ký tự mà không phải là một nhân vật từ Unicode Dưới Python 2, bạn muốn cũng phải đặt cờ UNICODE
cho điều này).
Cách bạn đang sử dụng thời gian là luôn luôn mở và đọc tệp.Bạn nên di chuyển công cụ đó đến phần '-s' để có được kết quả có ý nghĩa –
Cảm ơn bạn, tất nhiên là bạn đúng. Vì điều này được thực hiện trong cả hai ví dụ, nên có lỗi (và, tôi vừa thử) giống nhau ở cả hai. Thật thú vị, tôi thấy rằng tiền biên dịch regex không tạo nên sự khác biệt. Tôi đã cập nhật các ví dụ về thời gian. –
Lưu ý rằng bạn không thể đặt cờ với re.sub; bạn phải sử dụng re.compile() để chỉ định cờ và gọi sub() trên kết quả. (Đây là một thiếu sót API lạ.) Câu trả lời của bạn sẽ tốt hơn khi xóa phiên bản "+"; nó không phải là những gì anh ta yêu cầu, vì vậy nó chỉ mất tập trung. –
Thay vì (x.isupper() or x.islower())
bạn sẽ có thể sử dụng x.isalpha()
. Phương pháp isalpha()
có thể trả lại True
cho '_'
(Tôi không nhớ có hay không) nhưng sau đó bạn sẽ chỉ kết thúc thay thế '_'
với '_'
để không gây hại. (Cảm ơn vì đã chỉ ra điều đó, KennyTM.)
Thực ra, nó có thể tự tính là '_' ký tự chữ cái, vì vậy có thể không. Hãy thử nó và xem. – MatrixFrog
Thay thế '_' bằng' _' (hoặc không) là vô hại. – kennytm
Tò mò về điều này vì lý do của riêng tôi, tôi đã viết kịch bản nhanh để kiểm tra các cách tiếp cận khác nhau được liệt kê ở đây cùng với việc loại bỏ lambda mà tôi mong đợi (không đúng) sẽ tăng tốc bản gốc dung dịch.
Phiên bản ngắn gọn là cách tiếp cận str.translate thổi những thứ khác đi. Như một giải pháp regex sang một bên, trong khi một giây thứ hai, là chính xác như được viết ở trên.
Đây là chương trình thử nghiệm của tôi:
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)
Và đây là kết quả:
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)
Giải pháp regex không chính xác vì nó thay thế một vài chữ cái liền kề chỉ bằng một dấu gạch dưới. Thả '+' sau lớp nhân vật và nó sẽ đúng dù chậm hơn. Tôi đoán câu hỏi là liệu bạn có thực sự muốn trải dài các dấu gạch dưới trong dây thay thế hay không ... –
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, ý tưởng rất hay. Hạn chế duy nhất tôi có thể nghĩ là điều này sẽ không hoạt động đúng trên chuỗi Unicode nếu các ký tự không phải ASCII phải được xem xét. –
@Tim, unicode cũng có một bản dịch - ngữ nghĩa là khác nhau mặc dù, hãy để tôi xem nếu tôi có thể làm cho nó hoạt động ... –
@Tim, phiên bản unicode là lên. Bản đồ dịch được xây dựng theo yêu cầu, vì vậy sẽ có ít và ít bị bỏ lỡ khi nhiều chuỗi được dịch. –