Регулярные выражения для парсинга пары значений разделённых двоеточием

Пытаюсь распарсить 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 шт):

Автор решения: MaxU
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, т.е. группа, которая не захватывается/сохраняется. Это удобно использовать когда надо найти одно из нескольких возможных значений и когда нам не нужно сохранять найденный паттерн

→ Ссылка
Автор решения: dIm0n

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_]+.

Чтобы не захватывать группу, надо написать её так:

(?:...)
→ Ссылка
Автор решения: timur

Мне кажется будет проще использовать не регулярки, а просто 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
→ Ссылка