Уменьшение жадности регулярного выражения в python

#python #regex #greedy #non-greedy

#python #регулярное выражение #жадный #нежадный

Вопрос:

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

Например, я пытаюсь получить просто имя файла .bar из строки, используя

 re.search('/(.*?).bar$', '/def_params/param_1M56/param/foo.bar')
  

Согласно документам Python re, *? это ungreedy версия * , поэтому я ожидал получить

 'foo'
  

возвращено для match.group(1) но вместо этого я получил

 'def_params/param_1M56/param/foo'
  

Чего я здесь не понимаю о жадности?

Ответ №1:

Чего вам не хватает, так это не столько жадности, сколько движков регулярных выражений: они работают слева направо, поэтому / совпадения выполняются как можно раньше, а .*? затем вынуждены работать оттуда. В этом случае лучшее регулярное выражение вообще не связано с жадностью (для этого вам нужно выполнить возврат; это сработает, но может занять действительно много времени, если в нем много косых черт), но более явный шаблон:

 '/([^/]*).bar$'
  

Ответ №2:

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

Вам нужно только имя файла перед расширением .bar и все после окончательного / . Это должно сделать:

 re.search(`/[^/]*.bar$`, '/def_params/param_1M56/param/foo.bar')
  

Что это делает, так это то, что оно соответствует / , затем нулю или более символов (насколько это возможно), которые не / являются, а затем .bar .

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

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

2. Упс 🙂 Отредактировано. Я надеюсь, что это не было причиной для понижения голоса, поскольку это не имеет отношения к проблеме.

3. снова поддержано 😉 хотя это может быть неуместно для этой проблемы, возможно, OP захочет использовать его (сейчас или позже) для сопоставления файлов с расширением bar или чем-то еще, и это тоже будет соответствовать .abar , например 🙂

Ответ №3:

Я не утверждаю, что так уж хорошо разбираюсь в нежадных операторах, но решением этой конкретной проблемы было бы использовать ([^ /] *?)

Ответ №4:

Регулярные выражения начинаются справа. Поместите .* в начале, и это должно сработать.

Ответ №5:

Мне нравится регулярное выражение, но здесь оно не нужно.

 path = '/def_params/param_1M56/param/foo.bar'
print  path.rsplit('/',1)[1].rsplit('.')[0]

path = '/def_params/param_1M56/param/fululu'
print  path.rsplit('/',1)[1].rsplit('.')[0]

path = '/def_params/param_1M56/param/one.before.two.dat'
print  path.rsplit('/',1)[1].rsplit('.',1)[0]
  

Результат

 foo
fululu
one.before.two
  

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

1. На самом деле я понял это сразу после того, как опубликовал вопрос. Все еще хотел узнать о природе жадности, хотя. Вы также можете просто использовать path.split('/')[-1].split('.')[0]

Ответ №6:

Другие люди отвечали на вопрос о регулярном выражении, но в этом случае есть более эффективный способ, чем регулярное выражение:

 file_name = path[path.rindex('/') 1 : path.rindex('.')]
  

Ответ №7:

попробуйте это для размера:

совпадение = повторный поиск(‘.*/(.*?). bar$’, ‘/def_params/param_1M56/param/foo.bar’)

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

1. Если вы уже используете '.*/ , я не думаю, что вам действительно нужно .*? . .* тоже будет работать 🙂 Не могли бы вы отредактировать свой вопрос, чтобы я мог снова поддержать вас?