отрицательное утверждение lookahead не работает в python
задачи:
- дано: список изображений filenames
- todo: создайте новый список с именами файлов, не содержащими слово "thumb" -т. е. только целевые изображения без миниатюр (с библиотекой изображений Pil - Python).
Я пробовал r".*(?!thumb).*"
но это не удалось.
я нашел решение (здесь, в stackoverflow), чтобы добавить ^
в regex и поставить .*
в отрицательный lookahead:r"^(?!.*thumb).*"
и теперь это работает.
дело в том, что я хотелось бы понять, почему мое первое решение не сработало, но я этого не делаю. Поскольку regexes достаточно сложны, я бы очень хотел их понять.
что я понимаю, так это то, что ^
сообщает синтаксическому анализатору, что следующее условие должно совпадать в начале строки. Но разве .*
в первом примере (не работает) также начинается в начале строки?
Я думал, что он начнется в начале строки и будет искать столько символов как это может до достижения "большого пальца". Если это так, он вернет несоответствие.
может кто-нибудь объяснить, почему r".*(?!thumb).*"
не работает, но r"^(?!.*thumb).*"
делает?
спасибо!
3 ответов
(черт, Джон избил меня. Ну что ж, вы все равно можете посмотреть на примеры)
как говорили другие ребята, регулярное выражение-не лучший инструмент для этой работы. Если вы работаете с filepaths, взгляните на os.путь.
что касается фильтрации файлов, которые вы не хотите, вы можете сделать if 'thumb' not in filename: ...
после того, как вы рассекали путь (где filename
- это str
).
и для потомков, вот мои мысли на эти выражения. r".*(?!thumb).*"
не работает, потому что .*
жадный, и lookahead получает очень низкий приоритет. Взгляните на это:
>>> re.search('(.*)((?!thumb))(.*)', '/tmp/somewhere/thumb').groups()
('/tmp/somewhere/thumb', '', '')
>>> re.search('(.*?)((?!thumb))(.*)', '/tmp/somewhere/thumb').groups()
('', '', '/tmp/somewhere/thumb')
>>> re.search('(.*?)((?!thumb))(.*?)', '/tmp/somewhere/thumb').groups()
('', '', '')
последний довольно странный...
другое выражение (r"^(?!.*thumb).*"
) работает, потому что .*
находится внутри lookahead, поэтому у вас нет никаких проблем с украденными персонажами. На самом деле вам даже не нужно ^
в зависимости от того, если вы используете re.match
или re.search
:
>>> re.search('((?!.*thumb))(.*)', '/tmp/somewhere/thumb').groups()
('', 'humb')
>>> re.search('^((?!.*thumb))(.*)', '/tmp/somewhere/thumb').groups()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'groups'
>>> re.match('((?!.*thumb))(.*)', '/tmp/somewhere/thumb').groups()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'groups'
может кто-нибудь объяснить, почему
r".*(?!thumb).*"
не работает, ноr"^(?!.*thumb).*"
делает?
первый всегда будет соответствовать как .*
будет потреблять всю строку (поэтому за ней не может последовать ничего, чтобы отрицательный lookahead потерпел неудачу). Второй немного запутан и будет соответствовать с самого начала строки, наибольшее количество символов, пока он не встретит "большой палец", и если это присутствует, то весь матч терпит неудачу, так как строка начинается с чего-то за ним следует "палец".
номер два-легче написать так:
'thumb' not in string
-
not re.search('thumb', string)
(вместо матча)
также, как я упоминал в комментариях, ваш вопрос говорит:
имена, не содержащие слово "большой палец"
таким образом, вы можете рассмотреть вопрос о том,thumbs up
должен быть исключен или нет.
игнорируя все биты о регулярных выражениях, ваша задача кажется довольно простой:
- дано: список имен файлов изображений
- todo: создайте новый список с именами файлов, не содержащими слово "thumb" - т. е. только целевые изображения без миниатюр (с Pil-Python Библиотека Изображений).
Если у вас есть список файлов, который выглядит примерно так:
filenames = [ 'file1.jpg', 'file1-thumb.jpg', 'file2.jpg', 'file2-thumb.jpg' ]
тогда вы можете получить список файлов не содержащий слово thumb, как это:
not_thumb_filenames = [ filename for filename in filenames if not 'thumb' in filename ]
Это то, что мы называем понимание, и является, по сути, сокращенный вариант:
not_thumb_filenames = []
for filename in filenames:
if not 'thumb' in filename:
not_thumb_filenames.append(filename)
регулярные выражения на самом деле не нужны для этой простой задачи.