У меня возникла небольшая проблема при попытке найти подстроку внутри строки с помощью регулярного выражения в Python. Рассмотрим следующую строку:
repr(a) = '\n02/07/2023, 14:52\nTest\nTest\nFin\n'
Я хотел бы найти подстроку от 2\n до \nFin\n. Обратите внимание, что он всегда будет заканчиваться на \nFin\n, но не всегда будет начинаться на 2\n. На самом деле он будет начинаться с X\n, где X — любой символ, отличный от пробела.
Вот таким образом мой код:
import re
a = """
02/07/2023, 14:52
Test
Test
Fin
"""
match = re.sub(r'[^ ]\n(.+)\n' + 'Fin' +'\n',r'** \1 **', a)
[^ ]: любой символ, не являющийся пробелом. \n(.+)\n' + 'Fin' +'\n': \n, за которым следует символ anny до \nFin\n.
Но это не работает...
Есть идеи? Проблема, кажется, исходит из пробела. Однако я пробовал разные решения, такие как «все цифры или буквы, за которыми следует \n», но не смог добиться успеха.
Вы просто пытаетесь удалить две строки, содержащие «Test»?






Согласен с Виктором, нужно знать в чем проблема. Кажется, работает. Вот что я вижу:
re.search(r'[^ ]\n(.+)\n' + 'Fin' +'\n', a)
показывает совпадение:
t\nTest\nFin\n
Это заменяется вашей строкой, создавая это:
02/07/2023, 14:52
Tes** Test **
это именно то, что я получаю от вызова re.sub.
Кажется, вы ожидаете, что (.+) будет соответствовать обеим строкам «Test», но точка не соответствует новой строке.
Я не уверен на 100% в вашем ожидаемом результате, но я подозреваю, как прокомментировал @samkamin, источник вашей проблемы в том, что . не соответствует новым строкам. Вместо этого вам нужно будет использовать [\s\S] (пробел и не пробел) для соответствия символу новой строки*, например:
>>> match = re.sub(r'\n.*[^ ]\n([\s\S]+)\nFin\n', r'** \1 **', a)
>>> print(match)
** Test
Test **
>>>
Я добавил новую строку и .* в начале, чтобы отбросить начальную новую строку в вашей тестовой строке и отметке времени, поскольку вы сказали, что хотите, чтобы было то, что было между отметкой времени и \nFin.
* Это расширение Python. Базовое регулярное выражение в других контекстах потребует (\n|.), но это неэффективно.
Пожалуйста, не используйте (.|\n)+, потому что это очень неэффективно. Лучше использовать .+ с re.S или [\s\S]+
@Thefourthbird Спасибо, что научил меня кое-чему!
@Thefourthbird Я включил ваше предложение.
Если я запускаю предоставленный код, я получаю следующий вывод.
02/07/2023, 14:52
Tes** Test **
Ошибка в вашем коде заключается в том, что re.sub заменяет совпадающее значение, а не только захваченное значение.
Итак, это соответствует следующему.
t
Test
Fin
"... Я хочу найти подстроку от 2\n до \nFin\n. ..."
Вы можете использовать однолинейный режим, также называемый точечным режимом.
Это приведет к тому, что . будет дополнительно соответствовать разделителям новой строки.
Вы можете использовать следующий шаблон.
[^ \r\n]$[\r\n]+^(.+?)[\r\n]+^Fin$
$ и ^ здесь обозначают конец и начало строки соответственно.
Вы можете использовать функцию Pattern.search, чтобы вернуть первое совпадение и захваченное значение из a.
a = """
02/07/2023, 14:52
Test
Test
Fin
"""
pattern = re.compile(r'[^ \r\n]$[\r\n]+^(.+?)[\r\n]+^Fin$', flags=re.M | re.S)
matches = pattern.search(a)
print(matches.group(1))
Выход
Test
Test
И, если у вас есть текст с несколькими вхождениями, вы можете использовать функцию Pattern.finditer.
a = """
02/07/2023, 14:52
Test
Test
Fin
02/07/2023, 14:52
ABC
123
Fin
02/07/2023, 14:52
DEF
456
Fin
"""
pattern = re.compile(r'[^ \r\n]$[\r\n]+^(.+?)[\r\n]+^Fin$', flags=re.M | re.S)
matches = pattern.finditer(a)
for match in matches:
print(match.group(1))
Выход
Test
Test
ABC
123
DEF
456
Что значит "не работает"? Он находит совпадение и заменяет его.