Регулярное выражение Python возвращает часть совпадения при использовании с re.findall

Я пытался научить себя Python и в настоящее время занимаюсь регулярными выражениями. Учебный текст, который я использовал, похоже, предназначен для обучения Perl или какому-то другому языку, отличному от Python, поэтому мне пришлось немного адаптировать выражения, чтобы они соответствовали Python. Однако я не очень опытен, и я столкнулся с проблемой, пытаясь заставить выражение работать.

Проблема заключается в поиске в тексте экземпляров цен, выраженных либо без десятичных знаков, 500 долларов, либо с десятичными знаками, 500,10 долларов.

Вот что рекомендует текст:

\$[0-9]+(\.[0-9][0-9])?

Воспроизводя текст, я использую этот код:

import re

inputstring = "$500.01"

result = re.findall( r'\$[0-9]+(\.[0-9][0-9])?', inputstring)

if result:
    print(result)
else:
    print("No match.")

Однако результат не 500,01 доллара, а скорее:

.01

Я нахожу это странным. Если я удалю круглые скобки и необязательную десятичную часть, все будет работать нормально. Итак, используя это:

\$[0-9]+\.[0-9][0-9]

Я получил:

$500.01

Как я могу заставить регулярное выражение возвращать значения с десятичными частями и без них?

Спасибо.


person Jordan H.    schedule 19.08.2015    source источник
comment
Теперь это хороший вопрос о регулярных выражениях.   -  person Two-Bit Alchemist    schedule 20.08.2015
comment
Джордан Х. добро пожаловать в SO. Очень приятно видеть, что пользователь в свой первый день публикует вопрос, который демонстрирует исследовательские усилия, хорошо сформулирован и соответствует рекомендациям SO.   -  person cezar    schedule 20.08.2015


Ответы (1)


Используйте группу без захвата:

result = re.findall( r'\$[0-9]+(?:\.[0-9][0-9])?', inputstring)
                                ^^ 

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

re.findall(pattern, string, flags=0)
Если в шаблоне присутствует одна или несколько групп, вернуть список групп; это будет список кортежей, если шаблон имеет более одной группы.

Обновить

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

r'\$[0-9]+(?:\.[0-9]{2})?'
                    ^^^

Или даже заменить [0-9] на \d:

r'\$\d+(?:\.\d{2})?'
person Wiktor Stribiżew    schedule 19.08.2015
comment
Я бы также заменил [0-9][0-9], что выглядит излишним, на [0-9]{2}, поскольку в цене всегда должно быть два десятичных знака, если они есть. - person cezar; 19.08.2015
comment
Я думал о том же в отношении вашего последнего редактирования. К сожалению, я не могу проголосовать больше одного раза. - person cezar; 20.08.2015
comment
Ваше предложение сработало. Кроме того, я новичок в stackoverflow, и я понимаю, что текст в поле для комментариев говорит, что не следует использовать это поле, чтобы сказать спасибо, но я не знаю, как еще выразить свою благодарность на этом сайте, поэтому я собираюсь все-таки сказать. Спасибо. - person Jordan H.; 20.08.2015
comment
@JordanH: рад помочь. Благодарность за SO означает голосование за ответы, которые полезны для вас, и принятие ответов, которые решают ваш вопрос. Удачи. - person Wiktor Stribiżew; 20.08.2015
comment
Хотя я не могу думать о реальном случае, но что должно произойти, если есть строка типа abc$500.01dolar. Это регулярное выражение все равно найдет $500,01. Если вы явно хотите найти только цены, которые начинаются с $ после пробела, а также имеют пробел после второго десятичного знака, регулярное выражение также должно соответствовать началу строки ^ и концу строки $. Я не хочу мудрить, а просто укажу на некоторые подводные камни ОП. - person cezar; 20.08.2015
comment
Если это проверка и вся строка должна содержать только цену в долларах США, ^\$\d+(?:\d{2})?$ будет работать. Я думаю, что здесь OP нужно получить все вхождения из большей строки. - person Wiktor Stribiżew; 20.08.2015