Hapus karakter kecuali angka dari string menggunakan Python?

142

Bagaimana cara menghapus semua karakter kecuali angka dari string?

Jan Tojnar
sumber
@ Jan Tojnar: Bisakah Anda memberi contoh?
João Silva
@JG: Saya memiliki gtk.Entry () dan saya ingin multiply float masuk ke dalamnya.
Jan Tojnar
1
@JanTojnar menggunakan metode re.sub sesuai jawaban dua dan secara eksplisit mencantumkan karakter mana yang akan disimpan misalnya re.sub ("[^ 0123456789 \.]", "", "Poo123.4and5fish")
Roger Heathcote

Jawaban:

112

Dalam Python 2. *, sejauh ini pendekatan tercepat adalah .translatemetode:

>>> x='aaa12333bb445bb54b5b52'
>>> import string
>>> all=string.maketrans('','')
>>> nodigs=all.translate(all, string.digits)
>>> x.translate(all, nodigs)
'1233344554552'
>>> 

string.maketransmembuat tabel terjemahan (string dengan panjang 256) yang dalam hal ini sama dengan ''.join(chr(x) for x in range(256))(hanya lebih cepat membuatnya ;-). .translatemenerapkan tabel terjemahan (yang di sini tidak relevan karena allpada dasarnya berarti identitas) DAN menghapus karakter yang ada di argumen kedua - bagian kunci.

.translatebekerja sangat berbeda pada string Unicode (dan string di Python 3 - Saya melakukan pertanyaan keinginan tertentu yang besar-rilis Python adalah kepentingan!) - tidak cukup sederhana ini, tidak cukup cepat ini, meskipun masih cukup bermanfaat.

Kembali ke 2. *, perbedaan kinerja sangat mengesankan ...:

$ 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

Mempercepat sebanyak 7-8 kali bukanlah hal yang mudah, jadi translatemetode ini layak untuk diketahui dan digunakan. Pendekatan non-RE populer lainnya ...:

$ python -mtimeit -s'x="aaa12333bb445bb54b5b52"' '"".join(i for i in x if i.isdigit())'
100000 loops, best of 3: 11.5 usec per loop

adalah 50% lebih lambat dari RE, sehingga .translatependekatan mengalahkannya dengan urutan besarnya.

Di Python 3, atau untuk Unicode, Anda perlu meneruskan .translatepemetaan (dengan ordinal, bukan karakter secara langsung, sebagai kunci) yang mengembalikan Noneapa yang ingin Anda hapus. Berikut cara mudah untuk mengungkapkannya untuk menghapus "semuanya kecuali" beberapa karakter:

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)

juga memancarkan '1233344554552'. Namun, meletakkan ini di xx.py kita memiliki ...:

$ 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

... yang menunjukkan keuntungan kinerja menghilang, untuk jenis tugas "penghapusan", dan menjadi penurunan kinerja.

Alex Martelli
sumber
1
@sunqiang, ya, tentu saja - ada alasan Py3k beralih ke Unicode sebagai tipe string teks THE, bukan string byte seperti di Py2 - alasan yang sama Java dan C # selalu memiliki meme "string berarti unicode" yang sama ... beberapa overhead, mungkin, tetapi dukungan yang JAUH lebih baik untuk apa saja kecuali bahasa Inggris! -).
Alex Martelli
29
x.translate(None, string.digits)sebenarnya menghasilkan 'aaabbbbbb', yang merupakan kebalikan dari apa yang dimaksudkan.
Tom Dalling
4
Mengomentari komentar dari Tom Dalling, contoh pertama Anda menyimpan semua karakter yang tidak diinginkan - berlawanan dengan apa yang Anda katakan.
Chris Johnson
3
@ RyanB.Lynch dkk, kesalahannya ada pada editor selanjutnya dan dua pengguna lain yang menyetujui edit tersebut , yang, sebenarnya, sepenuhnya salah. Dikembalikan.
Nick T
2
overriding allbuiltin ... tidak yakin tentang itu!
Andy Hayden
202

Gunakan re.sub, seperti ini:

>>> import re
>>> re.sub('\D', '', 'aas30dsa20')
'3020'

\D cocok dengan karakter non-digit apa pun, jadi, kode di atas, pada dasarnya menggantikan setiap karakter non-digit untuk string kosong.

Atau Anda dapat menggunakan filter, seperti (dengan Python 2):

>>> filter(str.isdigit, 'aas30dsa20')
'3020'

Karena di Python 3, filtermengembalikan iterator alih-alih a list, Anda dapat menggunakan yang berikut ini:

>>> ''.join(filter(str.isdigit, 'aas30dsa20'))
'3020'
João Silva
sumber
re jahat dalam tugas sederhana seperti itu, yang kedua adalah yang terbaik menurut saya, karena metode 'adalah ...' adalah yang tercepat untuk string.
f0b0s
contoh filter Anda terbatas pada py2k
SilentGhost
2
@ f0b0s-iu9-info: apakah Anda menghitung waktunya? pada mesin saya (py3k) dua kali lebih cepat daripada filter dengan isdigit, generator dengan isdigtsetengah jalan di antara mereka
SilentGhost
@SilentGhost: Terima kasih, saya menggunakan IDLE dari py2k. Sudah diperbaiki sekarang.
João Silva
1
@asmaier Cukup gunakan runtuk string mentah:re.sub(r"\D+", "", "aas30dsa20")
Mitch McMabers
66
s=''.join(i for i in s if i.isdigit())

Varian generator lain.

f0b0s
sumber
Membunuhnya .. + 1 Akan lebih baik jika lamda digunakan
Barath Ravikumar
Jika Anda ingin memasukkan karakter khusus apa pun, misalnya menyertakan negatif atau desimal - lakukan ini:s = ''.join(i for i in s if i.isdigit() or i in '-./\\')
Eugene Chabanov
17

Anda dapat menggunakan filter:

filter(lambda x: x.isdigit(), "dasdasd2313dsa")

Di python3.0 Anda harus bergabung dengan ini (agak jelek :()

''.join(filter(lambda x: x.isdigit(), "dasdasd2313dsa"))
freiksenet.dll
sumber
hanya di py2k, di py3k itu mengembalikan generator
SilentGhost
konversikan strke listuntuk memastikannya berfungsi pada py2 dan py3:''.join(filter(lambda x: x.isdigit(), list("dasdasd2313dsa")))
Luiz C.
13

di sepanjang garis jawaban bayer:

''.join(i for i in s if i.isdigit())
SilentGhost
sumber
Tidak, ini tidak akan berfungsi untuk angka negatif karena -bukan digit.
Oli
12

Anda dapat dengan mudah melakukannya menggunakan Regex

>>> import re
>>> re.sub("\D","","£70,000")
70000
Aminah Nuraini
sumber
Sejauh ini cara termudah
Iorek
6
Apa bedanya dengan jawaban João Silva, yang diberikan 7 tahun sebelumnya?
jww
7
x.translate(None, string.digits)

akan menghapus semua digit dari string. Untuk menghapus huruf dan menyimpan angka, lakukan ini:

x.translate(None, string.letters)
Terje Molnes
sumber
3
Saya mendapatkan TypeError: translate () mengambil tepat satu argumen (2 diberikan). Mengapa pertanyaan ini mendapat suara positif dalam kondisinya saat ini cukup membuat frustrasi.
Bobort
translate diubah dari python 2 menjadi 3. Sintaks yang menggunakan metode ini di python 3 adalah x.translate (str.maketrans ('', '', string.digits)) dan x.translate (str.maketrans ('', '' , string.ascii_letters)). Tak satu pun dari strip ini ruang putih. Saya tidak akan merekomendasikan pendekatan ini lagi ...
ZaxR
6

Op tersebut menyebutkan di komentar bahwa dia ingin menyimpan tempat desimal. Ini dapat dilakukan dengan metode re.sub (sesuai dengan jawaban terbaik kedua dan IMHO) dengan secara eksplisit mencantumkan karakter yang akan disimpan misalnya

>>> re.sub("[^0123456789\.]","","poo123.4and5fish")
'123.45'
Roger Heathcote
sumber
Bagaimana dengan "poo123.4and.5fish"?
Jan Tojnar
Dalam kode saya, saya memeriksa jumlah periode dalam string input dan meningkatkan kesalahan jika itu lebih dari 1.
Roger Heathcote
4

Versi cepat untuk 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)

Berikut perbandingan performa vs. 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

Jadi ini sedikit lebih dari 3 kali lebih cepat daripada regex, bagi saya. Ini juga lebih cepat daripada di class Delatas, karena defaultdictsemua pencariannya di C, daripada Python (lambat). Ini versi itu di sistem saya yang sama, untuk perbandingan.

$ python3.3 -mtimeit -s'import xx; x="aaa12333bb445bb54b5b52"' 'x.translate(xx.DD)'
100000 loops, best of 3: 13.6 usec per loop
rescdsk
sumber
3

Gunakan ekspresi generator:

>>> s = "foo200bar"
>>> new_s = "".join(i for i in s if i in "0123456789")
bayer
sumber
sebagai gantinya lakukan''.join(n for n in foo if n.isdigit())
shxfee
2

Jelek tapi berhasil:

>>> s
'aaa12333bb445bb54b5b52'
>>> a = ''.join(filter(lambda x : x.isdigit(), s))
>>> a
'1233344554552'
>>>
Gant
sumber
kenapa kau lakukan list(s)?
SilentGhost
@SilentGost itu kesalahpahaman saya. sudah diperbaiki terima kasih :)
Gant
Sebenarnya, dengan metode ini, saya rasa Anda tidak perlu menggunakan "gabung". filter(lambda x: x.isdigit(), s)bekerja dengan baik untuk saya. ... oh, itu karena saya menggunakan Python 2.7.
Bobort
2

Anda dapat membaca setiap karakter. Jika berupa digit, masukkan ke dalam jawaban. The str.isdigit() Metode adalah cara untuk mengetahui apakah karakter adalah digit.

your_input = '12kjkh2nnk34l34'
your_output = ''.join(c for c in your_input if c.isdigit())
print(your_output) # '1223434'
yoelvis
sumber
apa bedanya dengan jawaban f0b0s? Anda harus mengedit jawaban itu sebagai gantinya jika Anda memiliki lebih banyak informasi untuk dibawa
chevybow
1
$ python -mtimeit -s'import re;  x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'

100000 loop, terbaik 3: 2,48 usec per loop

$ python -mtimeit -s'import re; x="aaa12333bab445bb54b5b52"' '"".join(re.findall("[a-z]+",x))'

100000 loop, terbaik 3: 2.02 usec per loop

$ python -mtimeit -s'import re;  x="aaa12333bb445bb54b5b52"' 're.sub(r"\D", "", x)'

100000 loop, terbaik 3: 2,37 usec per loop

$ python -mtimeit -s'import re; x="aaa12333bab445bb54b5b52"' '"".join(re.findall("[a-z]+",x))'

100000 loop, terbaik 3: 1,97 usec per loop

Saya telah mengamati bahwa join lebih cepat daripada sub.

AnilReddy
sumber
Mengapa Anda mengulangi kedua metode tersebut dua kali? Dan dapatkah Anda menjelaskan bagaimana jawaban Anda berbeda dari yang diterima?
Jan Tojnar
Keduanya menghasilkan keluaran yang sama. Tapi, saya hanya ingin menunjukkan bahwa join lebih cepat dari sub metode dalam hasil.
AnilReddy
Mereka tidak melakukannya, kode Anda melakukan yang sebaliknya. Dan juga Anda memiliki empat pengukuran tetapi hanya dua metode.
Jan Tojnar
0

Bukan satu baris tapi sangat sederhana:

buffer = ""
some_str = "aas30dsa20"

for char in some_str:
    if not char.isdigit():
        buffer += char

print( buffer )
Josh
sumber
0

Saya menggunakan ini. 'letters'harus berisi semua huruf yang ingin Anda singkirkan:

Output = Input.translate({ord(i): None for i in 'letters'}))

Contoh:

Input = "I would like 20 dollars for that suit" Output = Input.translate({ord(i): None for i in 'abcdefghijklmnopqrstuvwxzy'})) print(Output)

Keluaran: 20

Gustav
sumber
0
my_string="sdfsdfsdfsfsdf353dsg345435sdfs525436654.dgg(" 
my_string=''.join((ch if ch in '0123456789' else '') for ch in my_string)
print(output:+my_string)

keluaran: 353345435525436654

Kokul Jose
sumber