Menghapus semua karakter non-numerik dari string dengan Python

Jawaban:

267
>>> import re
>>> re.sub("[^0-9]", "", "sdkjh987978asd098as0980a98sd")
'987978098098098'
Ned Batchelder
sumber
89
itu bisa re.sub (r "\ D", "", "sdkjh987978asd098as0980a98sd")
newacct
2
dan itu bisa berupa: dari impor kembali sub
James Koss
89

Tidak yakin apakah ini cara yang paling efisien, tetapi:

>>> ''.join(c for c in "abc123def456" if c.isdigit())
'123456'

Bagian ini ''.joinberarti menggabungkan semua karakter yang dihasilkan bersama tanpa karakter di antaranya. Kemudian sisanya adalah pemahaman daftar, di mana (seperti yang mungkin Anda bisa tebak) kita hanya mengambil bagian-bagian dari string yang sesuai dengan kondisi isdigit.

Mark Rushakoff
sumber
1
Itu sebaliknya. Saya pikir maksud Anda "tidak c.isdigit ()"
Ryan R. Rosario
7
Hapus semua non-numerik == pertahankan hanya angka.
Mark Rushakoff
10
Saya suka bahwa pendekatan ini tidak perlu menarik kembali, untuk fungsi sederhana ini.
triunenature
Perhatikan bahwa tidak seperti implementasi menggunakan str.translate, solusi ini bekerja di kedua python 2.7 dan 3.4. Terima kasih!
Alex
1
Saya lebih suka alternatif ini. Menggunakan regex sepertinya berlebihan bagi saya.
alfredocambera
18

Ini harus berfungsi untuk objek string dan unicode di Python2, dan string dan byte di Python3:

# python <3.0
def only_numerics(seq):
    return filter(type(seq).isdigit, seq)

# python ≥3.0
def only_numerics(seq):
    seq_type= type(seq)
    return seq_type().join(filter(seq_type.isdigit, seq))
tzot
sumber
9

Hanya untuk menambahkan opsi lain ke dalam campuran, ada beberapa konstanta yang berguna di dalam stringmodul. Meskipun lebih bermanfaat dalam kasus lain, mereka dapat digunakan di sini.

>>> from string import digits
>>> ''.join(c for c in "abc123def456" if c in digits)
'123456'

Ada beberapa konstanta dalam modul, termasuk:

  • ascii_letters (abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ)
  • hexdigits (0123456789abcdefABCDEF)

Jika Anda menggunakan konstanta-konstanta ini dengan berat, ada baiknya untuk menyamarkannya menjadi a frozenset. Itu memungkinkan pencarian O (1), bukan O (n), di mana n adalah panjang konstanta untuk string asli.

>>> digits = frozenset(digits)
>>> ''.join(c for c in "abc123def456" if c in digits)
'123456'
Tim McNamara
sumber
'' .join (c untuk c di "abc123def456" jika c.isdigit ()) bekerja di python saya 3.4
Eino Mäkitalo
7

@Ned Batchelder dan @newacct memberikan jawaban yang benar, tetapi ...

Untuk jaga-jaga jika Anda memiliki koma (,) desimal (.) Di string Anda:

import re
re.sub("[^\d\.]", "", "$1,999,888.77")
'1999888.77'
kennyut
sumber
5

Pendekatan tercepat, jika Anda perlu melakukan lebih dari satu atau dua operasi penghapusan seperti itu (atau bahkan hanya satu, tetapi pada string yang sangat panjang! -), adalah bergantung pada translatemetode string, meskipun perlu persiapan:

>>> import string
>>> allchars = ''.join(chr(i) for i in xrange(256))
>>> identity = string.maketrans('', '')
>>> nondigits = allchars.translate(identity, string.digits)
>>> s = 'abc123def456'
>>> s.translate(identity, nondigits)
'123456'

The translateMetode berbeda, dan mungkin anak laki-laki lebih sederhana sederhana untuk digunakan, pada string Unicode daripada di string byte, btw:

>>> unondig = dict.fromkeys(xrange(65536))
>>> for x in string.digits: del unondig[ord(x)]
... 
>>> s = u'abc123def456'
>>> s.translate(unondig)
u'123456'

Anda mungkin ingin menggunakan kelas pemetaan daripada dict yang sebenarnya, terutama jika string Unicode Anda berpotensi berisi karakter dengan nilai ord yang sangat tinggi (yang akan membuat dict terlalu besar ;-). Sebagai contoh:

>>> class keeponly(object):
...   def __init__(self, keep): 
...     self.keep = set(ord(c) for c in keep)
...   def __getitem__(self, key):
...     if key in self.keep:
...       return key
...     return None
... 
>>> s.translate(keeponly(string.digits))
u'123456'
>>> 
Alex Martelli
sumber
2
(1) Jangan angka ajaib kode keras; s / 65536 / sys.maxunicode / (2) Dict itu tanpa syarat "terlalu besar" karena input "berpotensi" berisi (sys.maxunicode - number_of_non_numeric_chars)entri. (3) pertimbangkan apakah string.digits mungkin tidak cukup yang mengarah pada kebutuhan untuk membuka modul unicodedata (4) pertimbangkan re.sub (r '(? U) \ D +', u '', teks) untuk kesederhanaan dan potensi mempercepat.
John Machin
2

Banyak jawaban yang benar tetapi jika Anda menginginkannya dalam float, langsung, tanpa menggunakan regex:

x= '$123.45M'

float(''.join(c for c in x if (c.isdigit() or c =='.'))

123.45

Anda dapat mengubah titik koma tergantung pada kebutuhan Anda.

ubah untuk ini jika Anda tahu nomor Anda bilangan bulat

x='$1123'    
int(''.join(c for c in x if c.isdigit())

1123

Alberto Ibarra
sumber