Я пытаюсь написать регулярное выражение, которое найдет значения валют в моем тексте. У меня есть значения, которые варьируются от 2 долларов до 2 240 000 000. Я пытаюсь написать выражение регулярного выражения, которое найдет все эти значения, но я терплю неудачу. Я попробовал что-то вроде:

^\{USD}?(\d*(\d\.?|\.\d{1,2}))$

Но не сработало. Я ценю любую помощь :)

РЕДАКТИРОВАТЬ: Для пояснения, у меня есть текст с несколькими долларовыми значениями, в диапазоне от 2 до 2 000 000 000.

Текст что-то вроде:

«Базовая покупка составляет 2,00 долл. США. (...) Сумма, равная 2 300 000 долл. США, которая относится к премиальному пакету. (...) Стране необходимо 300,00 долл. США ...»

Я хочу найти и извлечь эти значения (USD + цифры) и сохранить его в список, каждое значение в качестве отдельного элемента. Спасибо

1
Vanj 9 Янв 2019 в 16:17

2 ответа

Лучший ответ

В вашем выражении есть несколько ошибок: ^\{USD}?(\d*(\d\.?|\.\d{1,2}))$

  1. \{USD}? на языке регулярных выражений это будет означать: ожидайте буквального символа {, за которым следует USD, за которым следует символ }, если таковой имеется. Если вы хотите иметь дополнительную группу USD, вы должны использовать скобки без \: (USD)?. Для этого можно использовать группу без захвата : (?:USD)?.

Это даст: ^(USD)?(\d*(\d\.?|\.\d{1,2}))$

  1. (\d\.?|\.\d{1,2}), вся группа должна быть повторена, чтобы соответствовать всей строке: (\d\.?|\.\d{1,2})*

Это даст: ^(USD)?(\d*(\d\.?|\.\d{1,2})*)$

  1. \d\.?: если это должно соответствовать части с разделителем тысяч, это должна быть запятая, а не точка в вашем примере: \d*,?

Это даст: ^(USD)?(\d*(\d,?|\.\d{1,2})*)$

  1. (\d*(\d: это не сработает, второй \d никогда не будет совпадать, потому что вся цифра будет поглощена первым \d*, вы можете использовать нежадный оператор ? вот так: (\d*?(\d но это некрасиво.

Это даст: ^(USD)?(\d*?(\d,?|\.\d{1,2})*)$, который может сработать для вас, но выглядит неоптимально.

Альтернативой может быть построение вашего регулярного выражения без предложения «или» с использованием следующих частей:

  1. Префикс: «USD», необязательный и с необязательным пробелом: (USD ?)?
  2. Неотъемлемая часть суммы перед разделителями тысяч: \d+
  3. Неотъемлемая часть суммы с разделителем тысяч, необязательный и повторяемый: (,\d+)*
  4. Десятичная часть, необязательно: (\.\d+)?

Что даст что-то вроде этого: (USD ?)?(\d+)(,\d+)*(\.\d+)?

Вы можете протестировать его на regex101.com

Вы можете дополнительно ограничить количество цифр в каждой части, чтобы избежать ложных срабатываний:

(USD ?)?(\d{1,3})(,\d{3})*(\.\d{1,2})?

Окончательная версия будет оптимизирована с помощью групп без захвата при необходимости:

(?:USD ?)?(?:\d{1,3})(?:,\d{3})*(?:\.\d{1,2})?

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

(?:USD ?)?(?:\d{1,3})(?:,\d{3})*(?:[.,]\d{1,2})?

Что соответствует каждому числу в вашем примере: Снимок экрана Regex 101

3
zakinster 9 Янв 2019 в 15:01

Хорошо начнем с

import re
text = "The base purchase is USD 2,00.00 (...) The amount equal to US 2,300,000 which refers to the premium package. (...) The country needs USD 300,00..."

Как предложил @zakinster, вы можете найти интересующие вас строковые числа:

regex = r"(?:USD)?(?:\d+,)*\d+(?:\.\d+)?"
numbers = re.findall(regex, text)

Затем, чтобы отфильтровать тот, который вы упомянули:

def toInteger(s): return int(s.split('.')[0].replace(',',''))

def numberBetween(string,lowerBound,upperBound): 
    intValue = toInteger(string)
    return True if intValue>lowerBound & intValue<upperBound else False

print(list(filter(lambda x: numberBetween(x,2,2240000000),numbers)))

Должен дать вам то, что вы хотите:

['2,00.00', '2,300,000', '300,00']
0
Etienne Herlaut 9 Янв 2019 в 14:19