Как захватить строки с помощью * или? с группами в регулярных выражениях Python

У меня есть str1 и str2 ниже, и я хочу использовать только одно регулярное выражение, которое будет соответствовать обоим. В случае str1 я также хочу иметь возможность захватывать количество портов QSFP

>>> str1='''4 48 48-port and 6 QSFP 10GigE Linecard 7548S-LC''' 
>>> str2='''4 48 48-port 10GigE Linecard 7548S-LC''' 
>>> 

Я хочу быть в состоянии захватить числа "4", "48", "6" (если присутствует) и "7548". Но я не могу захватить "6" с помощью "?" метасимволом.

Когда я не использую метасимвол, захват работает для str1, но тогда я могу использовать это регулярное выражение, потому что он не будет работать для str2:

>>> re.search(r'^(\d+)\s+(\d+)\s+.*(?:(\d+)\s+QSFP).*\s+(\d+)S-LC', str1, re.I|re.M).group(3) 
'6' 
>>>

Это работает, даже когда я использую "+", чтобы указать одно вхождение, но опять же, это не будет работать для str2:

>>> re.search(r'^(\d+)\s+(\d+)\s+.*(?:(\d+)\s+QSFP)+.*\s+(\d+)S-LC', str1, re.I|re.M).group(3) 
'6' 
>>>

Когда я использую "?" чтобы соответствовать 0 или 1 вхождению, перехват не выполняется даже для str1:

>>> re.search(r'^(\d+)\s+(\d+)\s+.*(?:(\d+)\s+QSFP)?.*\s+(\d+)S-LC', str1, re.I|re.M).group(3) 
>>>

4 ответа

Моя интерпретация проблемы заключалась в том, что OP хотел регулярное выражение, которое будет соответствовать обеим строкам и возвращать число в.group(1), если оно существует (как в str1). Я полагаю, что проблема заключалась в том, что он / она не смогли ни захватить "6" на стр.1, но и сопоставить стр2.

Я получил это из некоторых быстрых проб и ошибок:

>>> str1='''4 48 48-port and 6 QSFP 10GigE Linecard 7548S-LC''' 
>>> str2='''4 48 48-port 10GigE Linecard 7548S-LC''' 
>>> re.search(r'^4\s+48\s+.*(?:(\d+)\s+QSFP)|.*-LC', str1, re.I|re.M).group(1)
'6'
>>> re.search(r'^4\s+48\s+.*(?:(\d+)\s+QSFP)|.*-LC', str2, re.I|re.M).group(1)
>>> # no error returned, implying a match was found.

Разница в том, что я "или" не захватывая паренов с.*

К сожалению, это делает регулярное выражение еще более трудным для понимания, но, возможно, это сработает для вас.

(отредактировано для полноты)

Я хочу быть в состоянии захватить числа "4", "48", "6" (если присутствует) и "7548". Но я не могу захватить "6" с помощью "?" метасимволом.

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

str1='''4 48 48-port and 6 QSFP 10GigE Linecard 7548S-LC'''
str2='''4 48 48-port 10GigE Linecard 7548S-LC'''
lines = [str1,str2]
nums = []
for l in lines:
    r = []
    bits = l.split()
    last_num = bits.pop()[:-4]
    _ = [r.append(i) for i in bits if i.isdigit()]
    r.append(last_num)
    nums.append(r)

>>> nums
[['4', '48', '6', '7548'], ['4', '48', '7548']]

Я не уверен, что именно ваше требование.

Это что-то вроде этого:

>>> str1 = "hello 12 world"
>>> str2 =  "hello world"
>>> obj = re.search(r'(\d+)',str1)
>>> obj.group(0)
'12'

Сейчас регистрируюсь str2 который не содержит никакого десятичного значения.

>>> obj = re.search(r'(\d+)',str2)
>>> if obj is not None:
...     print obj.group(0)
... else:
...     print "not found"
...
not found
>>>

Я думаю, что проблема в том, что .* съедает бит QSFP, и из-за ? у него нет стимула когда-либо отступать. Изменение .* не жадным .*? (удивительно - мне по крайней мере) не помогло. Перемещение .* однако внутри группы без захвата действительно помогает:

>>> re.match(r'^4\s+48\s+(?:.*(\d+)\s+QSFP)?.*-LC', str1, re.I|re.M).group(1)
'6'
>>> re.match(r'^4\s+48\s+(?:.*(\d+)\s+QSFP)?.*-LC', str2, re.I|re.M).group(1)
>>> 
Другие вопросы по тегам