2012-01-26 2 views
5

Я пытаюсь разобрать некоторые docstrings.regex: string с дополнительными частями

В качестве примера это строки документации:

Test if a column field is larger than a given value 
    This function can also be called as an operator using the '>' syntax 

    Arguments: 
     - DbColumn self 
     - string or float value: the value to compare to 
      in case of string: lexicographic comparison 
      in case of float: numeric comparison 
    Returns: 
     DbWhere object 

Оба Arguments и Returns детали не являются обязательными. Я хочу, чтобы мое регулярное выражение возвращало как группы описание (первые строки), часть Arguments (если имеется) и часть Returns (если имеется).

Регулярное выражение У меня сейчас:

m = re.search('(.*)(Arguments:.*)(Returns:.*)', s, re.DOTALL) 

и работает в случае, если все три части присутствуют, но не как только Arguments или Returns части не доступны. Я пробовал несколько вариантов с неживыми модификаторами, такими как ??, но безрезультатно.

Edit: Когда Arguments и Returns части присутствуют, я на самом деле хотел бы только, чтобы соответствовать тексту после Arguments: и Returns: соответственно.

Спасибо!

+1

Является ли заказ всегда фиксированным? I. e., «Аргументы» всегда после стандартного текста и перед «Возвращает»? –

+0

Да, заказ всегда исправлен. – BioGeek

ответ

7

Try с:

re.search('^(.*?)(Arguments:.*?)?(Returns:.*)?$', s, re.DOTALL) 

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

Кроме того, если вы используете нежирный модификатор в первой группе шаблона, он будет соответствовать кратчайшей возможной подстроке, которая для .* является пустой строкой. Вы можете преодолеть это, добавив конец конца строки ($) в конце шаблона, который заставляет первую группу соответствовать как можно меньше символов, чтобы удовлетворить шаблон, то есть всю строку, когда нет Arguments и нет Returns разделы, и все до этих разделов, если они есть.

Edit: хорошо, если вы просто хотите, чтобы захватить текст после в Arguments: и Returns: лексем, вам придется подвернуть в пару более группами. Мы не будем использовать все группы, так называя их -с <?P<name> нотации (другой знак вопроса, Argh!) - начинает иметь смысл:

>>> m = re.search('^(?P<description>.*?)(Arguments:(?P<arguments>.*?))?(Returns:(?P<returns>.*))?$', s, re.DOTALL) 
>>> m.groupdict()['description'] 
"Test if a column field is larger than a given value\n This function can also be called as an operator using the '>' syntax\n\n " 
>>> m.groupdict()['arguments'] 
'\n  - DbColumn self\n  - string or float value: the value to compare to\n   in case of string: lexicographic comparison\n   in case of float: numeric comparison\n ' 
>>> m.groupdict()['returns'] 
'\n  DbWhere object' 
>>> 
+0

Работает как очарование! Как бы вы изменили регулярное выражение, если для необязательных частей я хочу только совместить текст после 'Аргументы' и' Возвраты'? – BioGeek

+0

Что-то вроде 're.search ('^ (. *?) (Аргументы: (. *?))? (Возвраты: (. *))? $', Doc, re.DOTALL)' работает, но я не знаю, t заботиться о возвращении второй и четвертой группы. – BioGeek

+0

Я отредактировал свой ответ. Просто назовите группы и забудьте о 'groups()', вместо этого используйте 'groupdict()'. – Chewie

3

Если вы хотите, чтобы соответствовать текст после необязательных Arguments: и Returns: разделов, И вы не хотите использовать (?P<name>...), чтобы назвать ваши группы захвата, вы также можете использовать (?:...), неконвертирующую версию обычных круглых скобок.

Регулярное выражение будет выглядеть следующим образом:

m = re.search('^(.*?)(?:Arguments:(.*?))?(?:Returns:(.*?))?$', doc, re.DOTALL) 
#      ^^     ^^ 

Согласно Python3 documentation:

(?:...)

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

Смежные вопросы