Нахождение последней группы в регулярном выражении - PullRequest
1 голос
/ 06 августа 2010

Три разделенных подчеркиванием элемента составляют мои строки: - сначала (буквы и цифры) - средний (буквы, цифры и подчеркивание) - последний (буквы и цифры)

Последний элемент является необязательным.

Примечание: мне нужно получить доступ к своим группам по их именам, а не по их индексам.

Примеры:

String : abc_def
first : abc
middle : def
last : None

String : abc_def_xyz
first : abc
middle: def
last: xyz

String : abc_def_ghi_jkl_xyz
first : abc
middle : def_ghi_jkl
last : xyz

Я не могу найти правильное регулярное выражение ...

Пока у меня есть две идеи:

Дополнительная группа

(?P<first>[a-z]+)_(?P<middle>\w+)(_(?P<last>[a-z]+))?

Но средняя группа совпадает до конца строки:

String : abc_def_ghi_jkl_xyz
first : abc
middle : def_ghi_jkl_xyz
last : vide

Использование '|'

(?P<first>[a-z]+)_(?P<middle>\w+)_(?P<last>[a-z]+)|(?P<first>[a-z]+)_(?P<middle>\w+)

Это выражение недопустимо: первая и средняя группы объявляются два раза. Хотя я мог бы написать выражение, повторно используя соответствующую группу из первой части выражения:

(?P<first>[a-z]+)_(?P<middle>\w+)_(?P<last>[a-z]+)|(?P=first)_(?P=middle)

Выражение допустимо, однако строки с первым и средним, как abc_def, не совпадают.

Примечание

Эти строки на самом деле являются частями пути, который мне нужно сопоставить. Это могут быть пути вроде:

  • / мой / путь / к / abc_def
  • / мой / путь / к / abc_def /
  • / мой / путь / к / abc_def / некоторые / другие / Stuf
  • / мой / путь / к / abc_def / некоторые / другие / Stuf /
  • / мой / путь / к / abc_def_ghi_jkl_xyz
  • / мой / путь / к / abc_def_ghi_jkl_xyz /
  • / мой / путь / к / abc_def_ghi_jkl_xyz / некоторые / другие / Stuf
  • / мой / путь / к / abc_def_ghi_jkl_xyz / некоторые / другие / Stuf /
  • ...

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

Большое спасибо!

Ответы [ 5 ]

4 голосов
/ 06 августа 2010

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

^(?P<first>[a-z]+)_(?P<middle>\w+?)(_(?P<last>[a-z]+))?$

По умолчанию \w+ будет соответствовать как много , насколько это возможно, что съедает остальную часть строки. Добавление ? говорит, что оно должно совпадать как маленький , насколько это возможно.

Спасибо Тиму Пицкеру за то, что он указал требования к якорям.

1 голос
/ 06 августа 2010

Используйте

^(?P<first>[a-z]+)_(?P<middle>\w+?)(_(?P<last>[a-z]+))?$

^ и $, чтобы закрепить регулярное выражение в начале и конце строки.

Из-за того, что \w+? ленивый, он может совпадать всего завозможно (но хотя бы один символ).

РЕДАКТИРОВАТЬ:

Для ваших измененных требований, которые теперь включают пути до и после этой строки, это работает:

^(.*?/)(?P<first>[a-z]+)_(?P<middle>\w+?)(_(?P<last>[a-z]+))?(/.*)?$

Кодобразец (Python 3.1):

import re
paths = ["/my/path/to/abc_def",
         "/my/path/to/abc_def/",
         "/my/path/to/abc_def/some/other/stuf",
         "/my/path/to/abc_def/some/other/stuf/",
         "/my/path/to/abc_def_ghi_jkl_xyz",
         "/my/path/to/abc_def_ghi_jkl_xyz/",
         "/my/path/to/abc_def_ghi_jkl_xyz/some/other/stuf",
         "/my/path/to/abc_def_ghi_jkl_xyz/some/other/stuf/"]

regex = re.compile(r"^(.*?/)(?P<first>[a-z]+)_(?P<middle>\w+?)(_(?P<last>[a-z]+))?(/.*)?$")

for path in paths:
    match = regex.match(path)
    print ("{}:\nBefore: {}\nFirst: {}\nMiddle: {}\nLast: {}\nAfter: {}\n".format(
           path, match.group(1), match.group("first"), match.group("middle"),
           match.group("last"), match.group(6)))

Выход:

/my/path/to/abc_def:
Before: /my/path/to/
First: abc
Middle: def
Last: None
After: None

/my/path/to/abc_def/:
Before: /my/path/to/
First: abc
Middle: def
Last: None
After: /

/my/path/to/abc_def/some/other/stuf:
Before: /my/path/to/
First: abc
Middle: def
Last: None
After: /some/other/stuf

/my/path/to/abc_def/some/other/stuf/:
Before: /my/path/to/
First: abc
Middle: def
Last: None
After: /some/other/stuf/

/my/path/to/abc_def_ghi_jkl_xyz:
Before: /my/path/to/
First: abc
Middle: def_ghi_jkl
Last: xyz
After: None

/my/path/to/abc_def_ghi_jkl_xyz/:
Before: /my/path/to/
First: abc
Middle: def_ghi_jkl
Last: xyz
After: /

/my/path/to/abc_def_ghi_jkl_xyz/some/other/stuf:
Before: /my/path/to/
First: abc
Middle: def_ghi_jkl
Last: xyz
After: /some/other/stuf

/my/path/to/abc_def_ghi_jkl_xyz/some/other/stuf/:
Before: /my/path/to/
First: abc
Middle: def_ghi_jkl
Last: xyz
After: /some/other/stuf/
0 голосов
/ 06 августа 2010

Спасибо всем за помощь!Два ключа моей проблемы, где: - добавление привязки в конце моего шаблона - превращение средней группы в не жадную.

Итак:

/start/of/the/path/(?P<a>[a-z]+)_(?P<b>\w+?)(_(?P<c>[a-z]+))?(/|$)

Таким образом, все следующие строкиподходящие:

/jobs/ads/abc_J123/previs/m_name
/jobs/ads/abc_J123/previs/m_name/
/jobs/ads/abc_J123/previs/m_name/some_stuff
/jobs/ads/abc_J123/previs/m_name/some_stuff/
/jobs/ads/abc_J123/previs/m_name/some_stuff/other_stuff
/jobs/ads/abc_J123/previs/m_name/some_stuff/other_stuff/
/jobs/ads/abc_J123/previs/m_name_stage
/jobs/ads/abc_J123/previs/m_name_stage/
/jobs/ads/abc_J123/previs/m_name_stage/some_stuff
/jobs/ads/abc_J123/previs/m_name_stage/some_stuff/
/jobs/ads/abc_J123/previs/m_name_stage/some_stuff/other_stuff
/jobs/ads/abc_J123/previs/m_name_stage/some_stuff/other_stuff/
/jobs/ads/abc_J123/previs/m_long_name_stage
/jobs/ads/abc_J123/previs/m_long_name_stage/
/jobs/ads/abc_J123/previs/m_long_name_stage/some_stuff
/jobs/ads/abc_J123/previs/m_long_name_stage/some_stuff/
/jobs/ads/abc_J123/previs/m_long_name_stage/some_stuff/other_stuff
/jobs/ads/abc_J123/previs/m_long_name_stage/some_stuff/other_stuff/

Большое спасибо за помощь!

0 голосов
/ 06 августа 2010

Не нужно быть таким сложным.

>>> s="abc_def_ghi_jkl_xyz"
>>> s.rsplit("_",1)
>>> splitted=s.split("_")
>>> first=splitted[0]
>>> last=splitted[-1]
>>> middle=splitted[1:-1]
>>> middle='_'.join(splitted[1:-1])
>>> print middle
def_ghi_jkl
0 голосов
/ 06 августа 2010

Попробуйте это регулярное выражение:

^(?P<first>[a-z]+)_(?P<middle>[a-z]+(?:_[a-z]+)*?)(?:_(?P<last>[a-z]+))?$

Вот контрольный пример:

import re

strings = ['abc_def', 'abc_def_xyz', 'abc_def_ghi_jkl_xyz']
pattern = '^(?P<first>[a-z]+)_(?P<middle>[a-z]+(?:_[a-z]+)*?)(?:_(?P<last>[a-z]+))?$'
for string in strings:
    m = re.match(pattern, string)
    print m.groupdict()

Вывод:

{'middle': 'def', 'last': None, 'first': 'abc'}
{'middle': 'def', 'last': 'xyz', 'first': 'abc'}
{'middle': 'def_ghi_jkl', 'last': 'xyz', 'first': 'abc'}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...