2008-10-20 2 views
0

Какой самый простой способ для меня преобразовать более простой формат регулярного выражения, используемый большинством пользователей в правильную строку регулярных re python?Строка Простая подстановка

В качестве примера, мне нужно, чтобы преобразовать это:

string = "*abc+de?" 

к этому:

string = ".*abc.+de.?" 

Конечно, я мог бы перебрать строки и создать другую строку символ за символом, но это неужели это неэффективный способ?

+0

Вы говорите о раскопках? Если да, то я думаю, что "?" должен быть преобразован в "." (т. е. один символ) – tzot 2008-10-20 12:13:34

ответ

5

Те не похож на регулярных выражения, которые вы пытаетесь перевести, они больше похожи на комки оболочки Unix. Для этого у Python есть module. Он не знает о синтаксисе «+», который вы использовали, но также и моя оболочка, и я думаю, что синтаксис нестандартен.

>>> import fnmatch 
>>> fnmatch.fnmatch("fooabcdef", "*abcde?") 
True 
>>> help(fnmatch.fnmatch) 
Help on function fnmatch in module fnmatch: 

fnmatch(name, pat) 
    Test whether FILENAME matches PATTERN. 

    Patterns are Unix shell style: 

    *  matches everything 
    ?  matches any single character 
    [seq] matches any character in seq 
    [!seq] matches any char not in seq 

    An initial period in FILENAME is not special. 
    Both FILENAME and PATTERN are first case-normalized 
    if the operating system requires it. 
    If you don't want this, use fnmatchcase(FILENAME, PATTERN). 

>>> 
0

Я хотел бы использовать replace:

def wildcard_to_regex(str): 
    return str.replace("*", ".*").replace("?", .?").replace("#", "\d") 

Это, вероятно, не самый эффективный способ, но он должен быть достаточно эффективным для большинства целей. Обратите внимание, что некоторые шаблоны шаблонов позволяют использовать классы символов, которые сложнее обрабатывать.

0

Это Perl example от этого. Это просто использование таблицы для замены каждой подстановочной конструкции соответствующим регулярным выражением. Я делал это сам ранее, но в C. Не следует слишком сильно переносить на Python.

1

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

Вам необходимо сгенерировать список замен, необходимых для преобразования из «пользовательского формата» в регулярное выражение. Для простоты обслуживания я бы хранить их в словаре, и как @Konrad Rudolph я бы просто использовать метод замены:

def wildcard_to_regex(wildcard): 
    replacements = { 
     '*': '.*', 
     '?': '.?', 
     '+': '.+', 
     } 
    regex = wildcard 
    for (wildcard_pattern, regex_pattern) in replacements.items(): 
     regex = regex.replace(wildcard_pattern, regex_pattern) 
    return regex 

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

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

2

.replacing() каждая из подстановочных знаков является быстрым способом, но что, если подстановочная строка содержит другие специальные символы регулярного выражения? например. кто-то ищет «my.thing *», вероятно, не означает, что ». для соответствия любому персонажу. И в худшем случае такие вещи, как круглые скобки для создания совпадений, скорее всего, нарушат вашу окончательную обработку совпадений регулярных выражений.

re.escape можно использовать для размещения литералов в регулярных выражениях. Сначала вам придется разделить символы подстановки. Обычным трюком для этого является использование re.split с подходящей скобкой, в результате чего в форме появляется список [литерал, подстановочный знак, литерал, подстановочный знак, литерал ...].

Пример код:

wildcards= re.compile('([?*+])') 
escapewild= {'?': '.', '*': '.*', '+': '.+'} 

def escapePart((parti, part)): 
    if parti%2==0: # even items are literals 
     return re.escape(part) 
    else: # odd items are wildcards 
     return escapewild[part] 

def convertWildcardedToRegex(s): 
    parts= map(escapePart, enumerate(wildcards.split(s))) 
    return '^%s$' % (''.join(parts)) 
Смежные вопросы