Làm thế nào tôi có thể loại bỏ tất cả các ký tự ngoại trừ số từ chuỗi?
Làm thế nào tôi có thể loại bỏ tất cả các ký tự ngoại trừ số từ chuỗi?
Câu trả lời:
Trong Python 2. *, cho đến nay, cách tiếp cận nhanh nhất là .translate
phương thức:
>>> x='aaa12333bb445bb54b5b52'
>>> import string
>>> all=string.maketrans('','')
>>> nodigs=all.translate(all, string.digits)
>>> x.translate(all, nodigs)
'1233344554552'
>>>
string.maketrans
tạo một bảng dịch (một chuỗi có độ dài 256) mà trong trường hợp này giống như ''.join(chr(x) for x in range(256))
(chỉ cần thực hiện nhanh hơn ;-). .translate
áp dụng bảng dịch (ở đây không liên quan vì all
về cơ bản có nghĩa là danh tính) VÀ xóa các ký tự có trong đối số thứ hai - phần chính.
.translate
hoạt động rất khác nhau trên các chuỗi Unicode (và các chuỗi trong Python 3 - Tôi thực sự muốn các câu hỏi được chỉ định phát hành chính của Python là gì!) - không hoàn toàn đơn giản, không hoàn toàn nhanh như vậy, mặc dù vẫn hoàn toàn có thể sử dụng được.
Quay lại 2. *, sự khác biệt về hiệu suất rất ấn tượng ...:
$ 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
Tăng tốc mọi thứ lên 7-8 lần hầu như không phải là đậu phộng, vì vậy translate
phương pháp này rất đáng để biết và sử dụng. Cách tiếp cận phi RE phổ biến khác ...:
$ python -mtimeit -s'x="aaa12333bb445bb54b5b52"' '"".join(i for i in x if i.isdigit())'
100000 loops, best of 3: 11.5 usec per loop
chậm hơn 50% so với RE, vì vậy .translate
cách tiếp cận đánh bại nó bằng một mức độ lớn hơn.
Trong Python 3 hoặc Unicode, bạn cần truyền .translate
ánh xạ (với các lệnh, không phải ký tự trực tiếp, dưới dạng các khóa) trả vềNone
những gì bạn muốn xóa. Đây là một cách thuận tiện để diễn đạt điều này để xóa "mọi thứ trừ" một vài ký tự:
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)
cũng phát ra '1233344554552'
. Tuy nhiên, đặt cái này vào xx.py chúng ta có ...:
$ 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
... Điều này cho thấy lợi thế về hiệu suất sẽ biến mất, đối với loại nhiệm vụ "xóa" này và trở thành giảm hiệu suất.
x.translate(None, string.digits)
thực sự dẫn đến kết quả 'aaabbbbbb'
ngược lại với dự định.
all
dựng sẵn ... không chắc chắn về điều đó!
Sử dụng re.sub
, như vậy:
>>> import re
>>> re.sub('\D', '', 'aas30dsa20')
'3020'
\D
khớp với bất kỳ ký tự không có chữ số nào, vì vậy, mã ở trên, về cơ bản thay thế mọi ký tự không có chữ số cho chuỗi trống.
Hoặc bạn có thể sử dụng filter
, như vậy (trong Python 2):
>>> filter(str.isdigit, 'aas30dsa20')
'3020'
Vì trong Python 3, filter
trả về một iterator thay vì mộtlist
, bạn có thể sử dụng như sau:
>>> ''.join(filter(str.isdigit, 'aas30dsa20'))
'3020'
isdigit
, trình tạo với isdigt
một nửa giữa chúng
r
cho chuỗi thô:re.sub(r"\D+", "", "aas30dsa20")
s=''.join(i for i in s if i.isdigit())
Một biến thể máy phát điện khác.
Bạn có thể sử dụng bộ lọc:
filter(lambda x: x.isdigit(), "dasdasd2313dsa")
Trên python3.0 bạn phải tham gia cái này (hơi xấu xí :()
''.join(filter(lambda x: x.isdigit(), "dasdasd2313dsa"))
str
để list
đảm bảo nó hoạt động trên cả py2 và py3:''.join(filter(lambda x: x.isdigit(), list("dasdasd2313dsa")))
x.translate(None, string.digits)
sẽ xóa tất cả các chữ số từ chuỗi. Để xóa các chữ cái và giữ các chữ số, hãy làm điều này:
x.translate(None, string.letters)
TypeError
: translate () mất chính xác một đối số (2 đã cho). Tại sao câu hỏi này được nêu lên trong trạng thái hiện tại của nó là khá bực bội.
Các op đề cập trong các ý kiến rằng ông muốn giữ vị trí thập phân. Điều này có thể được thực hiện với phương thức re.sub (theo câu trả lời tốt nhất thứ hai và IMHO) bằng cách liệt kê rõ ràng các ký tự để giữ, ví dụ:
>>> re.sub("[^0123456789\.]","","poo123.4and5fish")
'123.45'
Phiên bản nhanh cho 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)
Đây là một so sánh hiệu suất so với 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
Vì vậy, nó nhanh hơn một chút so với regex một chút, đối với tôi. Nó cũng nhanh hơn class Del
ở trên, bởi vì defaultdict
tất cả các tra cứu của nó trong C, thay vì (chậm) Python. Đây là phiên bản trên cùng một hệ thống của tôi, để so sánh.
$ python3.3 -mtimeit -s'import xx; x="aaa12333bb445bb54b5b52"' 'x.translate(xx.DD)'
100000 loops, best of 3: 13.6 usec per loop
Xấu xí nhưng hoạt động:
>>> s
'aaa12333bb445bb54b5b52'
>>> a = ''.join(filter(lambda x : x.isdigit(), s))
>>> a
'1233344554552'
>>>
list(s)
vậy
filter(lambda x: x.isdigit(), s)
làm việc tốt cho tôi ... Ồ, đó là vì tôi đang sử dụng Python 2.7.
$ python -mtimeit -s'import re; x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'
100000 vòng, tốt nhất là 3: 2,48 usec mỗi vòng
$ python -mtimeit -s'import re; x="aaa12333bab445bb54b5b52"' '"".join(re.findall("[a-z]+",x))'
100000 vòng, tốt nhất là 3: 2,02 usec mỗi vòng
$ python -mtimeit -s'import re; x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'
100000 vòng, tốt nhất là 3: 2,37 usec mỗi vòng
$ python -mtimeit -s'import re; x="aaa12333bab445bb54b5b52"' '"".join(re.findall("[a-z]+",x))'
100000 vòng, tốt nhất là 3: 1,97 usec mỗi vòng
Tôi đã quan sát thấy rằng tham gia là nhanh hơn phụ.
Bạn có thể đọc từng nhân vật. Nếu nó là chữ số, sau đó đưa nó vào câu trả lời. Các str.isdigit()
phương pháp là một cách để biết nếu một nhân vật là chữ số.
your_input = '12kjkh2nnk34l34'
your_output = ''.join(c for c in your_input if c.isdigit())
print(your_output) # '1223434'
Tôi đã sử dụng này. 'letters'
nên chứa tất cả các chữ cái mà bạn muốn loại bỏ:
Output = Input.translate({ord(i): None for i in 'letters'}))
Thí dụ:
Input = "I would like 20 dollars for that suit"
Output = Input.translate({ord(i): None for i in 'abcdefghijklmnopqrstuvwxzy'}))
print(Output)
Đầu ra:
20