Python Как искать подстроку со специальными символами? и * (как RexExp) - PullRequest
1 голос
/ 17 октября 2019

Мне следует отфильтровать строковый массив по подстроке и двум распознаваемым символам для ? и *.

? - один любой символ

* - любое количестволюбых символов

На примере данных ['baab', 'abbb', 'fc', 'AA'] он должен работать как:

'?b' -> ['baab', 'abbb']
'?a' -> ['baab']
'c?' -> []
'b??b' -> ['baab']
'???' -> ['baab', 'abbb']
'b*b' -> ['baab', 'abbb']
'***' -> ['baab', 'abbb', 'fc', 'AA']

Я не могу использовать оператор in. Какой самый простой способ решить это? Возможно, это должен быть RegExp (но я не уверен) или что-то еще.

Ответы [ 3 ]

0 голосов
/ 17 октября 2019

Вы должны использовать регулярные выражения: для любого символа используйте одну точку - для любого количества любых символов используйте одну точку, за которой следует звезда - для 0 или 1 символа, используйте одну точку, за которой следует знак опроса.

import re
define shortlist (pattern, list):
    return [s for s in list if re.search(pattern, s)]

mylist = ['baab', 'abbb', 'fc', 'AA']
l = shortlist('.b', mylist)  # l = ['baab', 'abbb']
l = shortlist('.a', mylist)  # l = ['baab']
l = shortlist('b..b', mylist)  # l = ['baab']
l = shortlist('b.*b', mylist)  # l = ['baab', 'abbb']
l = shortlist('.{3}', mylist) # l = ['baab', 'abbb']

См. https://docs.python.org/3/library/re.html для полной ссылки.

0 голосов
/ 17 октября 2019

вы можете исправить шаблон, заменив '?'с . и * с .*? в recognizable character patterns и вернуть любое substring, которое содержит хотя бы одно совпадение (re.search):

import re

example = ['baab', 'abbb', 'fc', 'AA']

def filter_by_pattern(elements, pattern):
    # convert `?` and `*` flags
    pattern = pattern.replace('?', '.').replace('*', '.*?')
    # you could make this a generator instead of list if you like
    return [substring for substring in elements if re.search(pattern, substring)]

print(filter_by_pattern(example , '?b'))
print(filter_by_pattern(example , '?a'))
print(filter_by_pattern(example , 'c?'))
print(filter_by_pattern(example , 'b??b'))
print(filter_by_pattern(example , '???' ))
print(filter_by_pattern(example , 'b*b' ))
print(filter_by_pattern(example , '***' ))

ВЫХОД:

['baab', 'abbb']
['baab']
[]
['baab']
['baab', 'abbb']
['baab', 'abbb']
['baab', 'abbb', 'fc', 'AA']
0 голосов
/ 17 октября 2019

Регулярное выражение: 1) уменьшить все последовательные * s, 2) re.escape части между ? и * и 3) заменить каждый * на .* и ? на. при компиляции регулярного выражения с модификатором re.DOTALL:

import re

def repl(m):
    res = "{}{}".format(re.escape(m.group(1)), m.group(2).replace("*", ".*").replace("?", "."))
    if m.group(3):
        res += re.escape(m.group(3))
    return res

def glob_to_regex(glob):
    glob = re.sub(r'\*{2,}', '*', glob)
    return '(?s)' + re.sub(r'([^?*]*)([*?]+)([^?*]+$)?', repl , glob)

l = ['baab', 'abbb', 'fc', 'AA', 'abb.']
print([x for x in l if re.search(glob_to_regex('?b*b'), x)])
print([x for x in l if re.search(glob_to_regex('?b*.'), x)])

См. Демонстрационную версию Python .

Здесь шаблон типа ?b*** будетпереводится в шаблон (?s).b.*, что означает:

  • (?s) - встроенный модификатор re.DOTALL, который также делает . разрывы строки соответствия
  • . - любой1 символ
  • b - b символ
  • .* - любые 0+ символов как можно больше.

Если вынеобходимо поддерживать любой шаблон glob вам нужен метод fnmatch.filter(names, pattern), который принимает шаблон glob (это то, что ваши ? и * здесь, подстановочные знаки).

Уникальная проблема здесь в том, что fnmatch глобусы должны совпадать со всем вводом, в то время как ваши шаблоны не зафиксированы.

Таким образом, вам нужно обернуть ваши шаблоны с помощью * s:

import fnmatch
l = ['baab', 'abbb', 'fc', 'AA']
print(fnmatch.filter(l, '*{}*'.format('?b')))
print(fnmatch.filter(l, '*{}*'.format('?a')))
print(fnmatch.filter(l, '*{}*'.format('c?')))
print(fnmatch.filter(l, '*{}*'.format('b??b')))
print(fnmatch.filter(l, '*{}*'.format('???')))
print(fnmatch.filter(l, '*{}*'.format('b*b')))
print(fnmatch.filter(l, '*{}*'.format('***')))

Output:

['baab', 'abbb']
['baab']
[]
['baab']
['baab', 'abbb']
['baab', 'abbb']
['baab', 'abbb', 'fc', 'AA']

См. демонстрационную версию Python .

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