Убрать все нечисловые символы (кроме ".") Из строки в Python - PullRequest
58 голосов
/ 04 июня 2009

У меня есть довольно хороший рабочий фрагмент кода, но мне было интересно, есть ли у кого-нибудь лучшие предложения о том, как это сделать:

val = ''.join([c for c in val if c in '1234567890.'])

Что бы вы сделали?

Ответы [ 6 ]

114 голосов
/ 04 июня 2009

Вы можете использовать регулярное выражение (используя модуль re), чтобы выполнить то же самое. Приведенный ниже пример соответствует серии [^\d.] (любой символ, который не является десятичной цифрой или точкой) и заменяет их пустой строкой. Обратите внимание, что если шаблон скомпилирован с флагом UNICODE, результирующая строка все равно может содержать не-ASCII чисел . Кроме того, результат после удаления «нечисловых» символов не обязательно является допустимым числом.

>>> import re
>>> non_decimal = re.compile(r'[^\d.]+')
>>> non_decimal.sub('', '12.34fe4e')
'12.344'
17 голосов
/ 04 июня 2009

Еще один «питонический» подход

filter( lambda x: x in '0123456789.', s )

но регулярное выражение быстрее.

13 голосов
/ 04 июня 2009

Вот пример кода:

$ cat a.py
a = '27893jkasnf8u2qrtq2ntkjh8934yt8.298222rwagasjkijw'
for i in xrange(1000000):
    ''.join([c for c in a if c in '1234567890.'])

$ cat b.py
import re

non_decimal = re.compile(r'[^\d.]+')

a = '27893jkasnf8u2qrtq2ntkjh8934yt8.298222rwagasjkijw'
for i in xrange(1000000):
    non_decimal.sub('', a)

$ cat c.py
a = '27893jkasnf8u2qrtq2ntkjh8934yt8.298222rwagasjkijw'
for i in xrange(1000000):
    ''.join([c for c in a if c.isdigit() or c == '.'])

$ cat d.py
a = '27893jkasnf8u2qrtq2ntkjh8934yt8.298222rwagasjkijw'
for i in xrange(1000000):
    b = []
    for c in a:
        if c.isdigit() or c == '.': continue
        b.append(c)

    ''.join(b)

И результаты сроков:


$ time python a.py
real    0m24.735s
user    0m21.049s
sys     0m0.456s

$ time python b.py
real    0m10.775s
user    0m9.817s
sys     0m0.236s

$ time python c.py
real    0m38.255s
user    0m32.718s
sys     0m0.724s

$ time python d.py
real    0m46.040s
user    0m41.515s
sys     0m0.832s

Похоже, что регулярное выражение пока победитель.

Лично я нахожу регулярное выражение столь же читабельным, как и понимание списка. Если вы делаете это всего несколько раз, вы, вероятно, получите больший успех при компиляции регулярного выражения. Делайте то, что сочетается с вашим кодом и стилем кодирования.

8 голосов
/ 22 февраля 2016

Простое решение - использовать регулярные выражения

import re 
re.sub("[^0-9^.]", "", data)
3 голосов
/ 04 января 2012
import string
filter(lambda c: c in string.digits + '.', s)
2 голосов
/ 04 июня 2009

Если набор символов был больше, использование наборов, как показано ниже, может быть быстрее. На самом деле это немного медленнее, чем a.py.

dec = set('1234567890.')

a = '27893jkasnf8u2qrtq2ntkjh8934yt8.298222rwagasjkijw'
for i in xrange(1000000):
    ''.join(ch for ch in a if ch in dec)

По крайней мере, в моей системе вы можете сэкономить немного времени (и памяти, если ваша строка была достаточно длинной, чтобы иметь значение), используя выражение генератора вместо понимания списка в a.py:

a = '27893jkasnf8u2qrtq2ntkjh8934yt8.298222rwagasjkijw'
for i in xrange(1000000):
    ''.join(c for c in a if c in '1234567890.')

О, и вот самый быстрый способ, который я нашел на этой тестовой строке (намного быстрее, чем регулярное выражение), если вы делаете это много, много раз и готовы мириться с накладными расходами на создание пары символов таблицы.

chrs = ''.join(chr(i) for i in xrange(256))
deletable = ''.join(ch for ch in chrs if ch not in '1234567890.')

a = '27893jkasnf8u2qrtq2ntkjh8934yt8.298222rwagasjkijw'
for i in xrange(1000000):
    a.translate(chrs, deletable)

В моей системе это выполняется за ~ 1,0 секунды, а регулярное выражение b.py - за 4,3 секунды.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...