Регулярные выражения для парсинга пары значений разделённых двоеточием
Пытаюсь распарсить URL с помощью регулярных выражений.
Допустим есть такой URL:
https:/test.ru/news/detail/int:id/
Необходимо с помощью регулярного выражения найти параметры, которые могут быть динамическими, они отличаются наличием двоеточия и записаны в формате:
<тип данных>:<название переменной>`
В примере выше динамический параметр, это int:id.
Для поиска таких параметров пытаюсь использовать такую регулярку. Она должна возвращать int:id и ничего больше:
r'(int|float|str|bool):[a-zA-Z_]+'
Но она возвращает мне какую-то дичь:
import re
regexp = r'(int|float|str|bool):[a-zA-Z_]+'
path = 'https:/test.ru/news/detail/int:id/'
print(re.search(regexp, path).groups())
# ('int',)
Так же пробовал:
regexp = r'((int|float|str|bool):[a-zA-Z_]+)'
print(re.search(regexp, path).groups())
# ('int:id', 'int')
regexp = r'((int|float|str|bool):([a-zA-Z_]+))'
print(re.search(regexp, path).groups())
# ('int:id', 'int', 'id')
regexp = r'((int|float|str|bool)(:[a-zA-Z_]+))'
print(re.search(regexp, path).groups())
# ('int:id', 'int', ':id')
regexp = r'((int|float|str|bool)(:)([a-zA-Z_]+))'
print(re.search(regexp, path).groups())
# ('int:id', 'int', ':', 'id')
И тысячи других вариаций скобок, которые тоже не работают.
Я не понимаю, почему они возвращают вообще что-то без двоеточия, если в регулярке чётко указано, что выражение должно содержать двоеточие и 1 или более символов после него. Пробовал тоже самое в JS, он при таких же регулярках другие результаты возвращает (но тоже дичь какую-то).
Что я делаю не так?
Ответы (3 шт):
pat = r'((?:int|float|str|bool):[a-zA-Z_]+)'
m = re.search(pat, path)
res = m.group(1) if m else None
результат:
In [60]: print(res)
int:id
UPD: пояснение:
(?: ...) - non-capturing group, т.е. группа, которая не захватывается/сохраняется. Это удобно использовать когда надо найти одно из нескольких возможных значений и когда нам не нужно сохранять найденный паттерн
groups() возвращает найденные группы. Группа - содержимое простых круглых скобок (...). В вашей регулярке
(int|float|str|bool):[a-zA-Z_]+
это будет int или float или т.д., но не :[a-zA-Z_]+, ведь эти символы не в скобках.
Здесь
((int|float|str|bool):([a-zA-Z_]+))
уже 3 группы: первая общая скобка, т.е. всё выражение, далее опять int или float или т.д. и далее [a-zA-Z_]+.
Чтобы не захватывать группу, надо написать её так:
(?:...)
Мне кажется будет проще использовать не регулярки, а просто str.split:
s = 'https:/test.ru/news/detail/int:id/'
print(s.split('/')[-2])
Если же вы хотите именно с помощью регулярки, то вы должны получить не все группы, а только первую, содержащую всю строку:
regexp = r'(?:int|float|str|bool):[a-zA-Z_]+'
print(re.search(regexp, path).groups(0)) #=> int:id