Как я могу получить все возможные подгруппы в python регулярное выражение? - PullRequest
2 голосов
/ 08 марта 2020

Я хотел бы получить все возможные подгруппы во время регулярного выражения findall: (group(subgroup))+. В настоящее время он возвращает только последние совпадения, например:

>>> re.findall(r'SOME_STRING_(([A-D])[0-9]+)+_[A-Z]+', 'SOME_STRING_A2B2C3_OTK')
[('C3', 'C')]

Теперь я должен сделать это в два этапа:

>>> match = re.match(r'SOME_STRING_(([A-D][0-9]+)+)_[A-Z]+', 'SOME_STRING_A2B2C3_OTK')
>>> re.findall(r'([A-D])[0-9]+', match.group(1))
['A', 'B', 'C']

Есть ли какой-либо метод, который может позволить мне получить тот же результат за один шаг?

Ответы [ 2 ]

2 голосов
/ 08 марта 2020

Поскольку (([A-D])[0-9]+)+ является группой повторных захватов , неудивительно, что возвращаются только результаты последнего матча.

Вы можете использовать Библиотека регулярных выражений PyPi (которую можно установить, набрав pip install regex в консоли / терминале и нажав клавишу ВВОД), а затем используйте:

import regex

results = regex.finditer(r'SOME_STRING_(([A-D])[0-9]+)+_[A-Z]+', 'SOME_STRING_A2B2C3_OTK')
print( [zip(x.captures(1),x.captures(2))  for x in results] )
# => [[('A2', 'A'), ('B2', 'B'), ('C3', 'C')]]

Свойство match.captures отслеживает все захваты.

Если вы можете использовать только re, вам нужно сначала извлечь все свои совпадения, а затем запустить второе регулярное выражение для них, чтобы извлечь нужные вам части:

import re
tmp = re.findall(r'SOME_STRING_((?:[A-D][0-9]+)+)_[A-Z]+', 'SOME_STRING_A2B2C3_OTK')
results = []
for m in tmp:
    results.append(re.findall(r'(([A-D])[0-9]+)', m))
print( results )
# => [[('A2', 'A'), ('B2', 'B'), ('C3', 'C')]]

См. Python демо

0 голосов
/ 08 марта 2020

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

  1. Длина SOME_STRING_ фиксирована . Это основано на данных примера, которые вы приводите, где SOME_STRING_ читает буквальную строку, а не регулярное выражение.
  2. Данные не содержат [E-Z] или других исключений в своей части «цифры алфавита» . Это основано на вашем рабочем 2-х строчном решении, которое должно было выдать ошибку AttributeError: 'NoneType' object has no attribute 'group', если существуют такие данные, как SOME_STRING_A1B2Z3_OTK. Однако об ошибке не сообщалось, поэтому я предполагаю, что у вас не было таких данных.

Если все вышеперечисленное выполнено, можно использовать одно регулярное выражение r"[0-9]+", чтобы выполнить прямое разбиение строки. Все цифры отбрасываются, потому что оператор + является жадным согласно официальной документации . Жадное совпадение теоретически может быть выполнено за один проход данных, поэтому эффективность должна быть удовлетворительной, если это действительно так. (У меня не было проверки деталей реализации.)

Решение

import re    
s = 'SOME_STRING_A10B20C30_OTK'  # len("SOME_STRING_") = 12 is fixed
                                 # may have multiple digits in between

re.compile(r"[0-9]+").split(s[12:])[:-1]  # discard the last element
# returns ['A', 'B', 'C']
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...