Perl, как регулярное выражение в Python - PullRequest
10 голосов
/ 14 апреля 2010

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

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

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

Ответы [ 5 ]

18 голосов
/ 14 апреля 2010

"Канонический" перевод 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() возвращает все подходящие группы, чтобы вы могли назначить их все одним глотком (используя список в Python,Точно так же, как использование массива в Perl, вероятно, будет более нормальным, но, поскольку вы решили использовать скаляры в Perl, вы можете сделать эквивалент и в Python.)сопоставить RE, что хорошо, если вы знаете, что все они совпадают (я не уверен, каково поведение вашего Perl, но я думаю, что вместо этого он будет «повторно использовать» значения предыдущей совпадающей строки, что является своеобразным ... если только сноваВы знаете, все линии совпадают ;-).Если вы хотите просто пропустить несовпадающие строки, измените последний оператор на следующие два:

    if mo:
        field_1, field_2, field_3 = mo.groups()
12 голосов
/ 14 апреля 2010

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

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

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

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

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

8 голосов
/ 14 апреля 2010

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)
6 голосов
/ 14 апреля 2010

И не забывайте, что в 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 голосов
/ 10 декабря 2014

Так же, как альтернативный пример, 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 - это словарь с ключами, соответствующими именам групп захвата («field1», «field2» и «field3») и значениями, соответствующими содержимому соответствующих групп захвата.

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

  • Для именованных групп захвата не имеет значения, измените ли вы шаблон регулярного выражения, чтобы добавить больше групп захвата или удалить существующие группы захвата, все по-прежнему помещается в словарь под правильными ключами. Но без именованных групп захвата вам придется дважды проверять присвоения переменных каждый раз, когда изменяется количество групп.
  • Именованные группы захвата делают ваши группы захвата самодокументирующимися.
  • Вы можете использовать цифры для обозначения групп, если хотите:
>>> 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'

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

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