Python Regex Найти группу соответствия диапазона нецифров после дефиса и, если диапазон отсутствует, игнорировать остаток шаблона - PullRequest
0 голосов
/ 09 июня 2018

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

v1.1.2-beta.2.zip
v1.1.2.zip

Я хочу написать регулярное выражение из одной строки, которое может найти группы совпадений в обоих типах.Например, если тип файла - первый почтовый индекс, я хотел бы, чтобы три группы соответствий выглядели следующим образом:

v1.1.2-beta.2.zip
Group 1: v1.1.2
Group 2: beta
Group 3. 2

или если вторая группа совпадений zip одна:

v1.1.2.zip
Group 1: v1.1.2

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

(v[0-9.]{0,}).([A-Za-z]{0,}).([0-9]).zip

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

([\D]{0,}(?=[-]) # Does not work

Может ли кто-нибудь указать мне правильное направление?

Ответы [ 3 ]

0 голосов
/ 09 июня 2018

Вы можете использовать re.findall:

import re
s = ['v1.1.2-beta.2.zip', 'v1.1.2.zip']
final_results = [re.findall('[a-zA-Z]{1}[\d\.]+|(?<=\-)[a-zA-Z]+|\d+(?=\.zip)', i) for i in s]
groupings = ["{}\n{}".format(a, '\n'.join(f'Group {i}: {c}' for i, c in enumerate(b, 1))) for a, b in zip(s, final_results)]
for i in groupings:
  print(i)
  print('-'*10)

Выход:

v1.1.2-beta.2.zip
Group 1: v1.1.2
Group 2: beta
Group 3: 2
----------
v1.1.2.zip
Group 1: v1.1.2.
----------

Обратите внимание, что результат, полученный из re.findall:

[['v1.1.2', 'beta', '2'], ['v1.1.2.']]
0 голосов
/ 09 июня 2018

Вот как я бы подошел к этому, используя re.search.Обратите внимание, что нам здесь не нужны обходные пути;просто довольно сложный шаблон будет делать эту работу.

import re

regex = r"(v\d+(?:\.\d+)*)(?:-(\w+)\.(\d+))?\.zip"

str1 = "v1.1.2-beta.2.zip"
str2 = "v1.1.2.zip"
match = re.search(regex, str1)

print(match.group(1))
print(match.group(2))
print(match.group(3))

print("\n")
match = re.search(regex, str2)

print(match.group(1))

v1.1.2
beta
2

v1.1.2

Демо

Если у вас нет опыта работы с регулярными выражениямипредоставление объяснения каждого шага, вероятно, не приведет вас к скорости.Я, однако, прокомментирую использование ?:, которое встречается в некоторых скобках.В этом контексте ?: говорит механизму регулярных выражений , а не , чтобы захватить то, что находится внутри.Мы делаем это, потому что вы хотите захватить (до) трех конкретных вещей.

0 голосов
/ 09 июня 2018

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

(v\d+(?:\.\d+)*)(?:[-]([A-Za-z]+))?((?:\.\d+)*)\.zip

Таким образом, получается три группы: первая версия, вторая необязательная: тире -, за которой следуют алфавитные символы, а затем необязательныйпоследовательность точек, за которыми следуют числа, и, наконец, .zip.

Если мы игнорируем суффикс \.zip (я полагаю, это довольно тривиально), то все равно есть три группы:

(v\d+(?:\.\d+)*): группа регулярных выражений, начинающаяся с v, за которым следует \d+ (одна или несколько цифр).Тогда у нас есть группа без захвата (группа, начинающаяся с (?:..), которая захватывает \.\d+ точку, за которой следует последовательность из одной или нескольких цифр. Мы повторяем такую ​​подгруппу ноль или более раз.

(?:[-]([A-Za-z]+))?: группа захвата, которая начинается с дефиса [-] и затем одного или нескольких символов [A-Za-z]. Однако группа захвата является необязательной (? в конце).

((?:\.\d+)*): группа, которая снова имеет такую ​​подгруппу \.\d+ без захвата, поэтому мы фиксируем точку, за которой следует последовательность цифр, и этот шаблон повторяется с нуля илибольше раз.

Например:

rgx = re.compile(r'(v\d+(?:\.\d+)*)([-][A-Za-z]+)?((?:\.\d+)*)\.zip')

Затем получаем:

>>> rgx.findall('v1.1.2-beta.2.zip')
[('v1.1.2', '-beta', '.2')]
>>> rgx.findall('v1.1.2.zip')
[('v1.1.2', '', '')]
...