Регулярное выражение для извлечения денежных значений из текста счета-фактуры

У меня есть регулярное выражение: \b[-+]?(?:\d{1,3}\.)(?:\d{3}\.)*(?:\d*) (Python), который соответствует числовым значениям в таких строках:

Amount: 12.234.55222 EUR
Some Text 123.222.22 maybe more text
1.245.455.2
22.34565 Could be at the beginning
It could be at the end of a string 21.1
221. It could be a number like this too (for US invoices, I saw a lot of different stuff)

Это то, чего я хочу. Но оно также соответствует первым двум частям даты, например: 08.05.2023

Я знаю, что это происходит из-за первой и последней группы, но не знаю, как это предотвратить. Я хочу соответствовать только тем ценностям, которые стоят сами по себе.
Может ли кто-нибудь указать мне правильное направление?

Редактировать: Забыл упомянуть, что пробовал с негативным взглядом сзади, но не сработало:

\b([-+]?(?:\d{1,3}\.)(?:\d{3}\.)*(?:\d*))(?!(?:\.d{4}))

Может я неправильно смотрю сзади?

Разделите на места и пользуйтесь ^([-+]?(?:\d{1,3}\.)(?:\d{3}\.)*(?:\d*))$? В противном случае, если у вас длинная строка, это станет слишком дорого. Это денежные ценности 12.234.55222 или 221.?

user24714692 12.07.2024 05:53

Это отличная идея, мне она нравится. Большое спасибо, я предоставлю код, когда закончу.

user3793935 12.07.2024 05:58

Ваши требования не очевидны из примеров, которые вы хотите сопоставить, и из одной строки, которую вы не хотите сопоставлять. Если вы точно укажете словами характеристики строк, которые вы хотите сопоставить с требуемым регулярным выражением, скорее всего, сразу выпадут. Обязательно укажите, хотите ли вы сопоставить всю строку или часть строки, если соблюдены определенные требования. Например, может ли строка быть "The string 12.234.55222 is an unusual phone number", а не просто "12.234.5522".

Cary Swoveland 12.07.2024 06:20

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

user3793935 12.07.2024 06:24

Обратите внимание, что (?!(?:\.d{4})), который является отрицательным опережением, можно упростить до (?!\.d{4}). Также «...но это не сработало...» расплывчато. Неясно, было ли регулярное выражение Python недействительным или оно не соответствовало строке, которая должна была сопоставляться, или соответствовало строке, которая не должна сопоставляться. Стремитесь быть точными во всем, что касается кодирования.

Cary Swoveland 12.07.2024 07:15
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
5
71
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

С идеей @user24714692 я сделал это следующим образом:

def float_check(text: str) -> bool:
    try:
        float(text)
        return True
    except ValueError:
            return False
        
def match_amount(amount: float, text: str) -> bool:
    pattern = r"^([-+]?(?:\d{1,3}\.)(?:\d{3}\.)*(?:\d*))$"
    # find all numbers, that match a pattern like i.e.: (123./,)*23

    # replace all comma, because the US is doing the numbers like this 291,234.23
    text = text.replace(",", ".")

    numbers = [
        pot_number for pot_number in text.split() if re.findall(pattern, pot_number)
    ]

    for number in numbers:
        # now replace all dots but the last one
        number = re.sub(r"\.(?=.*\.)", "", number)
        # and convert the numbers to float, and check if the number equals the given amount
        if float_check(number) and float(number) == amount:
            return True
    return False
    
print(match_amount(23.45, "some text with numbers here"))

Сейчас работает нормально, большое спасибо.

Я предположил, что строки должны соответствовать одному из форматов, заданных в шести примерах. Например, я предположил, что "12.234.55222" представляет строки, состоящие из двух цифр, за которыми следует точка, за которой следуют три цифры, за которыми следует точка, за которой следуют пять цифр.

Вы можете сопоставить регулярное выражение

^[+-]?(?:\d\.\d{3}\.\d{3}\.\d|\d{2}\.(?:\d{3}\.\d{5}|\d{6}\.\d|\d{2}\.\d)|\d{3}\.(?:\d{3}\.\d{2})?)$

Демо

Я написал выражение по ссылке в расширенном режиме или режиме со свободным интервалом, чтобы его было легче читать и чтобы оно было самодокументируемым.

Если примеры могут быть частями строк (а не всей строкой), замените ^ двумя отрицательными просмотрами назад, (?<!.)(?<!\d), и замените $ отрицательным просмотром вперед, (?![.\d]).

Ах, извините, мне нужно немного уточнить вопрос. Строки не обязательно должны находиться в конце/начале строки. Может быть что-то вроде этого: Сумма: 123.222,22 евро. Но для случая, который я представил, он работает нормально. Обновлено: теперь вопрос более ясен, все равно спасибо за помощь.

user3793935 12.07.2024 07:44

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

Cary Swoveland 12.07.2024 11:16

Другие вопросы по теме