вернуть строку с первым совпадением Regex

90

Я хочу получить первое совпадение регулярного выражения.

В этом случае у меня получился список:

text = 'aa33bbb44'
re.findall('\d+',text)

['33', '44']

Я мог извлечь первый элемент списка:

text = 'aa33bbb44'
re.findall('\d+',text)[0]

'33'

Но это работает, только если есть хотя бы одно совпадение, иначе я получу ошибку:

text = 'aazzzbbb'
re.findall('\d+',text)[0]

IndexError: список индекса вне допустимого диапазона

В этом случае я мог бы определить функцию:

def return_first_match(text):
    try:
        result = re.findall('\d+',text)[0]
    except Exception, IndexError:
        result = ''
    return result

Есть ли способ получить этот результат без определения новой функции?

Луис Рамон Рамирес Родригес
источник
Для меня принятый ответ не сработал. Мне пришлось удалить доступ к индексу массива и len(re.findAll)==0вместо этого использовать проверку.
Вишал,

Ответы:

104

Вы можете встроить ''значение по умолчанию в свое регулярное выражение, добавив |$:

>>> re.findall('\d+|$', 'aa33bbb44')[0]
'33'
>>> re.findall('\d+|$', 'aazzzbbb')[0]
''
>>> re.findall('\d+|$', '')[0]
''

Также работает с re.searchуказанными другими:

>>> re.search('\d+|$', 'aa33bbb44').group()
'33'
>>> re.search('\d+|$', 'aazzzbbb').group()
''
>>> re.search('\d+|$', '').group()
''
Стефан Почманн
источник
Отлично, имеет ли search / .group какое-либо преимущество перед findall / [0]?
Луис Рамон Рамирес Родригес
6
@LuisRamonRamirezRodriguez Ну, он может остановиться, как только найдет совпадение, не должен обрабатывать остальную часть текста и не должен хранить все совпадения. Так это эффективнее. Кроме того, это буквально «то, что вы хотите» , как сказал @TimPeters. Это может быть преимуществом, когда вы или кто-то другой в какой-то момент прочитаете его и задаетесь вопросом: «Почему был findallиспользован?» .
Stefan Pochmann
43

Если вам нужно только первое совпадение, используйте re.searchвместо re.findall:

>>> m = re.search('\d+', 'aa33bbb44')
>>> m.group()
'33'
>>> m = re.search('\d+', 'aazzzbbb')
>>> m.group()
Traceback (most recent call last):
  File "<pyshell#281>", line 1, in <module>
    m.group()
AttributeError: 'NoneType' object has no attribute 'group'

Затем вы можете использовать mв качестве условия проверки как:

>>> m = re.search('\d+', 'aa33bbb44')
>>> if m:
        print('First number found = {}'.format(m.group()))
    else:
        print('Not Found')


First number found = 33
Стальной кулак
источник
12

Я бы пошел с:

r = re.search("\d+", ch)
result = return r.group(0) if r else ""

re.searchв любом случае ищет только первое совпадение в строке, поэтому я думаю, что это делает ваше намерение немного более ясным, чем использование findall.

Билл
источник
7

Вам вообще не следует использовать .findall()- .search()это то, что вы хотите. Он находит самое левое совпадение, которое вы хотите (или возвращает, Noneесли совпадения не существует).

m = re.search(pattern, text)
result = m.group(0) if m else ""

Хотите ли вы поместить это в функцию, зависит от вас. Это необычно , чтобы хотеть вернуть пустую строку , если совпадение не найдено, поэтому ничего подобного не встраивается. Это невозможно запутаться о том , .search()на своих находках матч (возвращается , Noneесли это не так, или SRE_Matchобъект если бы это было).

Тим Питерс
источник
3

Ты можешь сделать:

x = re.findall('\d+', text)
result = x[0] if len(x) > 0 else ''

Обратите внимание, что ваш вопрос не совсем связан с регулярным выражением. Скорее, как безопасно найти элемент в массиве, если его нет.

кетан виджайваргия
источник
2
Я бы заменил len (x)> 0 здесь просто на x.
Ульф Аслак,
1

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

def return_first_match(text):
    result = re.findall('\d+',text)
    result = result[0] if result else ""
    return result
Марко Мачич
источник