Perl, как регулярное выражение в Python

В Perl я бы сделал что-то подобное для того, чтобы использовать разные поля в регулярном выражении, разделяя разные поля на() и получая их с помощью $

foreach $line (@lines)
{
 $line =~ m/(.*?):([^-]*)-(.*)/;
  $field_1 = $1
  $field_2 = $2
  $field_3 = $3
}

Как я могу сделать что-то подобное в Python?

Ответ 1

"Канонический" перевод вашего фрагмента на Python...:

import re

myre = re.compile(r'(.*?):([^-]*)-(.*)')
for line in lines:
    mo = myre.search(line)
    field_1, field_2, field_3 = mo.groups()

Импортирование re является обязательным (импорт обычно выполняется в верхней части модуля, но это необязательно). Предварительная компиляция RE необязательна (если вместо этого вы используете функцию re.search, она будет компилировать ваш шаблон "на лету" ), но рекомендуется (поэтому вы не полагаетесь на кеш модуля скомпилированных объектов RE для своей производительности, а также в порядке иметь объект RE и вызывать его методы, которые чаще встречаются в Python).

Вы можете использовать либо метод match (который всегда пытается совместить с запуском, независимо от того, начинается или нет ваш шаблон с помощью '^'), либо метод search (который пытается найти что-то в любом месте); с вашим шаблоном они должны быть эквивалентными (но я не уверен на 100%).

Метод .groups() возвращает все сопоставляемые группы, поэтому вы можете назначить их все в одном gulp (используя список в Python, как и использование массива в Perl, вероятно, будет более нормальным, но поскольку вы решили использовать скаляры в Perl вы тоже можете сделать в Python).

Это приведет к ошибке с исключением, если какая-либо строка не соответствует RE, и это нормально, если вы знаете, что все они соответствуют (я не уверен, что такое поведение вашего Perl, но я думаю, что он "повторно использовал" предыдущий сопоставляя значения строк, что является своеобразным... если только вы не узнаете, что все строки соответствуют;-). Если вы хотите просто пропустить несогласованные строки, измените последнее утверждение на следующие два:

    if mo:
        field_1, field_2, field_3 = mo.groups()

Ответ 2

В Perl вам будет гораздо лучше использовать массив, чем суффикс кучи скаляров с числами. Например.

foreach my $line ( @lines ) { 
    my @matches = ( $line =~ m/(.*?):([^-]*)-(.*)/ );
    ...
}

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

match = re.search( '(.*?):([^-]*)-(.*)', line )

Затем ваши совпадения будут доступны в match.group(1), match.group(2) и т.д.

Ответ 3

Python поддерживает регулярные выражения с помощью модуля re. Метод re.search() возвращает MatchObject, который имеет методы типа group(), которые вы можете использовать для извлечения информации о группе захвата.

Например:

m = re.search(r'(.*?):([^-]*)-(.*)', line)
field_1 = m.group(1)
field_2 = m.group(2)
field_3 = m.group(3)

Ответ 4

И не забывайте, что в Python, TIMTOWTDI;)

import re
p = re.compile(r'(\d+)\.(\d+)')
num_parts = p.findall('11.22   333.444') # List of tuples.
print num_parts                          # [('11', '22'), ('333', '444')]

Ответ 5

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

Чтобы использовать именованную группу захвата, просто добавьте ?P<the_name_of_the_group> в открывающую скобку группы захвата.

Это позволяет легко получить все ваши совпадения в словаре:

>>> import re
>>> x = re.search("name: (?P<name>\w+) age: (?P<age>\d+)", "name: Bob age: 20")
>>> x.groupdict()
{'age': '20', 'name': 'Bob'}

Здесь пример OP, измененный для использования названных групп захвата

import re

find_fields_regex = re.compile(r'(?P<field1>.*?):(?P<field2>[^-]*)-(?P<field3>.*)')
for line in lines:
    search_result = find_fields_regex.search(line)
    all_the_fields = search_result.groupdict()

Теперь all_the_fields - словарь с ключами, соответствующими именам группы захвата ( "поле1", "поле2" и "поле3" ) и значениям, соответствующим содержимому соответствующих групп захвата.

Почему вам следует выбирать имена групп захвата

  • С именованными группами захвата не имеет значения, измените ли вы шаблон регулярного выражения, чтобы добавить больше групп захвата или удалить существующие группы захвата, все по-прежнему помещается в словарь под правильными клавишами. Но без названных групп захвата вам нужно дважды проверять свои назначения переменных каждый раз, когда число групп изменяется.
  • Именованные группы захвата делают ваши группы захвата самодокументированными.
  • Вы все равно можете использовать номера для ссылки на группы, если хотите:
>>> import re
>>> x = re.search("name: (?P<name>\w+) age: (?P<age>\d+)", "name: Bob age: 20")
>>> x.groupdict()
{'age': '20', 'name': 'Bob'}
>>> x.group(1)
'Bob'
>>> x.group(2)
'20'

Некоторые хорошие ресурсы регулярных выражений: