Сопоставление регулярных выражений для значений между двумя шаблонами не возвращает все экземпляры, когда значения являются последовательными

#python #regex

Вопрос:

Я пытаюсь найти все экземпляры числа в уравнении. И для этого я написал этот скрипт на python:

 re.findall(fr"([- */(]|^)({val})([- */)]|$)", equation)
 

Теперь, когда я даю ему это: 20 5-20 , и выполняю поиск 20 , результат будет таким, как ожидалось: [('', '20', ' '), ('-', '20', '')]
Но когда я просто делаю 20 20-5 это, это больше не работает , и я получаю только первый экземпляр: [('', '20', ' ')]

Я не понимаю, почему, это даже не проблема 20 быть в начале и в конце, например, это 5-20*4-20/3 все равно 20 будет очень хорошо сочетаться. Это просто не работает, когда значение повторяется последовательно

как мне это исправить?

Спасибо

Комментарии:

1. Что это {val} должно здесь означать?

2. это форматирование строк python с использованием f-строк, просто игнорируйте его и думайте о {val} как о 20 в этом примере

Ответ №1:

Причина, по которой ваш шаблон изначально не работает 20 20-5 , заключается в том, что класс символов после сопоставления первого вхождения 20 фактически потребляет

После его использования для второго вхождения 20 сразу после него эта часть шаблона [- */(]|^) не может совпадать, так как нет символа, соответствующего классу символов, и его нет в начале строки.

Используя 20, например, на месте {val} , вы можете использовать поисковые запросы, которые не потребляют значение, а только утверждают, что оно присутствует.

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

 (?:(?<=[- */(])|^)20(?=[- */)]|$)
 

Демонстрация регулярных выражений

 import re

strings = [
    "20 5-20",
    "20 20-5"
]
val = 20
pattern = fr"(?:(?<=[- */(])|^){val}(?=[- */)]|$)"

for equation in strings:
    print(re.findall(pattern, equation))
 

Выход

 ['20', '20']
['20', '20']
 

Ответ №2:

Я предлагаю просто найти все числа (целое десятичное) в вашем выражении, а затем отфильтровать определенные значения:

 inp = "20 5-20*3.20"
matches = re.findall(r'd (?:.d )?', inp)
matches = [x for x in matches if x == '20']
print(matches)  # ['20', '20']
 

Каждое число в вашей формуле должно быть окружено только арифметическими символами, круглыми скобками или пробелами, все из которых не являются символами слов.

Комментарии:

1. это работает! но проблема в том, что я тоже допускаю нецелые числа (например, 3.20 не должно совпадать, но это происходит, если используется b). На этой ноте, как получилось, что ваша работает, а моя-нет, когда идея точно такая же?

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

Ответ №3:

Я думаю, что нашел ответ, но все еще не уверен, насколько он верен или почему он работает, а мой-нет :/

 re.findall(fr"(?:(?<=[=- */(])|^)({val})(?:(?=[=- */)])|$)", equation
 

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