Как вы фильтруете строку так, что возвращаются только символы в вашем списке? - PullRequest
22 голосов
/ 15 мая 2009

Представьте себе строку, такую ​​как 'Agh # $% #% 2341- -! Zdrkfd', и я только хочу выполнить некоторые операции с ней, чтобы возвращались только строчные буквы (в качестве примера), что в этом случае принесите "ghzdrkfd".

Как ты это делаешь в Python? Очевидным способом было бы создать список символов от 'a' до 'z', затем выполнить итерацию по символам в моей строке и построить новую строку, символ за символом, только из моего списка. Это кажется примитивным.

Мне было интересно, подходят ли регулярные выражения. Замена нежелательных символов кажется проблематичной, и я предпочитаю белый список, а не черный. Функция .match не кажется подходящей. Я просмотрел соответствующую страницу на сайте Python, но не нашел способа, который подходит.

Если регулярные выражения не подходят и правильный подход является цикличным, есть ли простая функция, которая «взрывает» строку в списке? Или я просто нажимаю на другой цикл?

Ответы [ 10 ]

32 голосов
/ 16 мая 2009

Если вы ищете эффективность. Использование функции translate - самое быстрое, что вы можете получить.

Может использоваться для быстрой замены символов и / или их удаления.

import string
delete_table  = string.maketrans(
    string.ascii_lowercase, ' ' * len(string.ascii_lowercase)
)
table = string.maketrans('', '')

"Agh#$%#%2341- -!zdrkfd".translate(table, delete_table)

В python 2.6: вам больше не нужен второй стол

import string
delete_table  = string.maketrans(
    string.ascii_lowercase, ' ' * len(string.ascii_lowercase)
)
"Agh#$%#%2341- -!zdrkfd".translate(None, delete_table)

Этот метод намного быстрее, чем любой другой. Конечно, вам нужно где-то хранить delete_table и использовать его. Но даже если вы не сохраняете и не создаете его каждый раз, он все равно будет работать быстрее, чем другие предложенные методы.

Чтобы подтвердить мои претензии, вот результаты:

for i in xrange(10000):
    ''.join(c for c in s if c.islower())

real    0m0.189s
user    0m0.176s
sys 0m0.012s

При запуске решения с регулярными выражениями:

for i in xrange(10000):
    re.sub(r'[^a-z]', '', s)

real    0m0.172s
user    0m0.164s
sys 0m0.004s

[По запросу] Если вы предварительно компилируете регулярное выражение:

r = re.compile(r'[^a-z]')
for i in xrange(10000):
    r.sub('', s)

real    0m0.166s
user    0m0.144s
sys 0m0.008s

Запуск метода перевода занял столько же раз:

real    0m0.075s
user    0m0.064s
sys 0m0.012s
18 голосов
/ 15 мая 2009
s = 'Agh#$%#%2341- -!zdrkfd'  
print ''.join(c for c in s if c.islower())

Строковые объекты являются итеративными; нет необходимости «взрывать» строку в списке. Вы можете поместить любое желаемое условие в понимание списка, и оно будет соответственно фильтровать символы.

Вы также можете реализовать это с помощью регулярных выражений, но это только скроет цикл. Библиотека регулярных выражений все равно должна будет проходить циклически по символам строки для их фильтрации.

5 голосов
/ 15 мая 2009

Использование регулярного выражения достаточно просто, особенно для этого сценария:

>>> import re
>>> s = 'ASDjifjASFJ7364'
>>> re.sub(r'[^a-z]+', '', s)
'jifj'

Если вы планируете делать это много раз, лучше скомпилировать регулярное выражение перед рукой:

>>> import re
>>> s = 'ASDjifjASFJ7364'
>>> r = re.compile(r'[^a-z]+')
>>> r.sub('', s)
'jifj'
4 голосов
/ 15 мая 2009
>>> s = 'Agh#$%#%2341- -!zdrkfd'
>>> ''.join(i for i in s if  i in 'qwertyuiopasdfghjklzxcvbnm')
'ghzdrkfd'
4 голосов
/ 15 мая 2009
s = 'ASDjifjASFJ7364'
s_lowercase = ''.join(filter(lambda c: c.islower(), s))
print s_lowercase #print 'jifj'
2 голосов
/ 19 марта 2017

Более общее и понятное решение - взять inputstring и отфильтровать его по whitelist символов:

inputstring = "Agh#$%#%2341- -!zdrkfd"
whitelist = "abcdefghijklmnopqrstuvwxyz"
remove = inputstring.translate(None, whitelist)
result = inputstring.translate(None, remove)
print result

Это печатает

ghzdrkfd

Первый string.translate удаляет все символы из белого списка из строки ввода. Это дает нам символы, которые мы хотим удалить. Второй вызов string.translate удаляет их из строки ввода и дает желаемый результат.

1 голос
/ 16 мая 2009

Вот одно решение, если вы особенно заинтересованы в работе со строками:

 s = 'Agh#$%#%2341- -!zdrkfd'
 lowercase_chars = [chr(i) for i in xrange(ord('a'), ord('z') + 1)]
 whitelist = set(lowercase_chars)
 filtered_list = [c for c in s if c in whitelist]

Белый список на самом деле является набором (а не списком) для эффективности.

Если вам нужна строка, используйте join ():

filtered_str = ''.join(filtered_list)

filter () - более общее решение. Из документации (http://docs.python.org/library/functions.html):

фильтр (функция, повторяемая)

Построить список из тех элементов итерируемых, для которых функция возвращает true. Итерируемым может быть либо последовательность, контейнер, который поддерживает итерацию, либо итератор. Если iterable является строкой или кортежем, результат также имеет этот тип; в противном случае это всегда список. Если для функции задано None, то предполагается, что тождественная функция, то есть все элементы итерируемого, которые являются ложными, удаляются.

Это был бы один из способов использования filter ():

filtered_list = filter(lambda c: c.islower(), s)
0 голосов
/ 28 апреля 2015
import string

print filter(string.lowercase.__contains__, "lowerUPPER")
print filter("123".__contains__, "a1b2c3")
0 голосов
/ 16 мая 2009
import string
print "".join([c for c in "Agh#$%#%2341- -!zdrkfd" if c in string.lowercase])
0 голосов
/ 15 мая 2009

Я бы использовал регулярное выражение. Для строчной буквы [a-z].

...