Как захватить строки с помощью * или? с группами в регулярных выражениях 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) 
>>>

person Sanjay BM    schedule 15.04.2012    source источник
comment
Комбинирование таких квантификаторов бессмысленно (0 или более копий 1 или более копий \d). Что ты на самом деле пытаешься сделать?   -  person geekosaur    schedule 15.04.2012
comment
Я думаю, что re.search(r'(\d+)', str1).group(0) достаточно.   -  person RanRag    schedule 15.04.2012
comment
Я хочу зафиксировать десятичное значение, ЕСЛИ оно отображается в 'str1', но я не хочу, чтобы регулярное выражение завершалось неудачно, если десятичного значения нет. Так что я действительно хочу, чтобы это ниже отображало десятичное значение: re.search (r '(\ d +)?', Str1) .group (1)   -  person Sanjay BM    schedule 15.04.2012
comment
Крайнее левое сопоставление означает, что \ d * (и аналогичные квантификаторы, которые разрешают сопоставления с пустой строкой) никогда не найдут цифры, если они не находятся в начале строки. Лучше всего использовать условную логику вне регулярного выражения.   -  person Mark Reed    schedule 15.04.2012
comment
Я смущен. Вы заявляете, что «также хотите захватить количество портов QSFP», но, согласно вашему примеру регулярных выражений, улавливаете ли вы что-нибудь кроме значения QSFP?   -  person hexparrot    schedule 15.04.2012
comment
В моем вопросе я упростил регулярное выражение, жестко закодировав числа «4» и «48» в начале строки. Это другие ценности, которые я на самом деле улавливаю.   -  person Sanjay BM    schedule 15.04.2012
comment
Обновите свой пост, чтобы указать что-то в этом роде, например, я хочу зафиксировать '4', '48', '48', '6' (если есть), '10', '74853' с помощью одного регулярного выражения. Или опустите некоторые в соответствии с вашими потребностями, например, мне нужно только 4,48 и 6 (если есть)   -  person hexparrot    schedule 15.04.2012
comment
использование тройных кавычек здесь неуместно, см. stackoverflow.com/questions/1520548/ и документацию по Python   -  person Shep    schedule 15.04.2012


Ответы (4)


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

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

>>> 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.

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

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

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

person ericcccc    schedule 15.04.2012

Я не совсем уверен, что вам нужно.

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

>>> 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
>>>
person RanRag    schedule 15.04.2012
comment
Я пытался упростить свой вопрос и теперь вижу путаницу, которую он может создать. Это то, что мне нужно: у меня ниже str1 и str2, и я хочу использовать только одно регулярное выражение, которое будет соответствовать обоим. Для str1 я хочу зафиксировать количество портов QSFP. ››› str1 = '' '4 48 48-портовых и 6 линейных карт QSFP 10GigE 7548S-LC' '››› str2 =' '' 4 48 48-портовых линейных карт 10GigE 7548S-LC '' '››› ››› повторный поиск (r' ^ 4 \ s + 48 \ s +. * (?: (\ D +) \ s + QSFP). * - LC ', str1, re. I | re.M) .group (1) '6' ››› ››› повторный поиск (r '^ 4 \ s + 48 \ s +. * (?: (\ D +) \ s + QSFP) ?. * -LC ', str1, re.I | re.M) .group (1) ››› - person Sanjay BM; 15.04.2012
comment
@ user1334085: включите этот комментарий в свой исходный вопрос. - person RanRag; 15.04.2012
comment
@ user1334085: и какой желаемый результат для str2 - person RanRag; 15.04.2012

Я хочу иметь возможность вводить числа «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']]
person Burhan Khalid    schedule 15.04.2012

Я думаю, проблема в том, что .* съедает бит 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)
>>> 
person Laurence Gonsalves    schedule 15.04.2012
comment
Прохладный!!! Это решило мою проблему. Я изначально пробовал. *? чтобы сделать его не жадным, и это тоже не сработало, к моему удивлению. Но ваше решение работает отлично. Спасибо. - person Sanjay BM; 15.04.2012