Удалить символы, кроме цифр из строки, используя Python? - PullRequest
114 голосов
/ 20 сентября 2009

Как удалить из строки все символы, кроме цифр?

Ответы [ 15 ]

161 голосов
/ 20 сентября 2009

Используйте re.sub, вот так:

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

\D соответствует любому нецифровому символу, поэтому вышеприведенный код по сути заменяет каждый нецифровый символ на пустую строку.

Или вы можете использовать filter, вот так (в Python 2k):

>>> filter(lambda x: x.isdigit(), "aas30dsa20")
'3020'

Поскольку в Python 3k filter возвращает итератор вместо list, вы можете использовать следующее:

>>> ''.join(filter(lambda x: x.isdigit(), "aas30dsa20"))
'3020'
104 голосов
/ 20 сентября 2009

В Python 2. * самый быстрый подход - это метод .translate:

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

string.maketrans создает таблицу перевода (строку длиной 256), которая в этом случае совпадает с ''.join(chr(x) for x in range(256)) (просто быстрее; ;). .translate применяет таблицу перевода (которая здесь неактуальна, поскольку all по существу означает идентичность) И удаляет символы, присутствующие во втором аргументе - ключевой части.

.translate работает очень по-разному для строк Unicode (и строк в Python 3 - I do хотел бы задать вопросы, которые представляют интерес для основного выпуска Python!) - не так просто, не довольно быстро, хотя все еще вполне пригодно для использования.

Возвращаясь к 2. *, разница в производительности впечатляет ...:

$ 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

Ускорение вещей в 7-8 раз - вряд ли арахис, поэтому метод translate стоит того, чтобы его изучить и использовать. Другой популярный не-RE подход ...:

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

на 50% медленнее, чем RE, поэтому подход .translate превосходит его более чем на порядок.

В Python 3 или для Unicode вам нужно передать .translate отображение (с порядковыми номерами, а не символами напрямую, как ключи), которое возвращает None для того, что вы хотите удалить. Вот удобный способ выразить это для удаления «всего, кроме» нескольких символов:

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)

также испускает '1233344554552'. Однако, поместив это в xx.py, мы получим ...:

$ 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

... который показывает, что преимущество в производительности исчезает для такого рода задач «удаления» и становится снижением производительности.

57 голосов
/ 20 сентября 2009
s=''.join(i for i in s if i.isdigit())

Еще один вариант генератора.

16 голосов
/ 20 сентября 2009

Вы можете использовать фильтр:

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

На python3.0 вы должны присоединиться к этому (довольно некрасиво :()

''.join(filter(lambda x: x.isdigit(), "dasdasd2313dsa"))
11 голосов
/ 20 сентября 2009

в соответствии с ответом Байера:

''.join(i for i in s if i.isdigit())
10 голосов
/ 30 августа 2016

Вы можете легко сделать это, используя Regex

>>> import re
>>> re.sub("\D","","£70,000")
70000
7 голосов
/ 04 марта 2013
x.translate(None, string.digits)

удалит все цифры из строки. Чтобы удалить буквы и сохранить цифры, сделайте следующее:

x.translate(None, string.letters)
5 голосов
/ 30 декабря 2012

В комментариях указывается, что он хочет сохранить десятичное место. Это можно сделать с помощью метода re.sub (согласно второму и наилучшему ответу IMHO) путем явного перечисления символов для сохранения, например,

>>> re.sub("[^0123456789\.]","","poo123.4and5fish")
'123.45'
4 голосов
/ 23 октября 2014

Быстрая версия для 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)

Вот сравнение производительности с регулярным выражением:

$ 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

Так что для меня это более чем в 3 раза быстрее, чем регулярное выражение. Это также быстрее, чем class Del выше, потому что defaultdict делает все свои поиски в C, а не (медленный) Python. Вот эта версия для моей системы, для сравнения.

$ python3.3 -mtimeit -s'import xx; x="aaa12333bb445bb54b5b52"' 'x.translate(xx.DD)'
100000 loops, best of 3: 13.6 usec per loop
2 голосов
/ 20 сентября 2009

Ужасно, но работает:

>>> s
'aaa12333bb445bb54b5b52'
>>> a = ''.join(filter(lambda x : x.isdigit(), s))
>>> a
'1233344554552'
>>>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...