Пакет Python, который делает glob с файлом ignore [duplicate]

В Python 3.x, raw_input был переименован в input, а Python 2.x input удален.

Это означает, что так же, как raw_input, input в Python 3.x всегда возвращает строковый объект.

Чтобы устранить проблему, вам нужно явно вставить эти вводы в целые числа, поместив их в int :

x = int(input("Enter a number: "))
y = int(input("Enter a number: "))

Кроме того, Python не нужен / не использует точки с запятой для завершения строк. Итак, если они не делают ничего позитивного.

4
задан fj123x 10 August 2014 в 15:31
поделиться

2 ответа

Вы на правильном пути: если вы хотите использовать шаблоны fnmatch -типов, вы должны использовать fnmatch.filter .

Но есть три проблемы, которые делают это не совсем тривиальным.

Во-первых, вы хотите применить несколько фильтров. Как ты это делаешь? Вызов filter несколько раз:

for ignore in ignore_files:
    filenames = fnmatch.filter(filenames, ignore)

Во-вторых, вы действительно хотите сделать reverse из filter: вернуть подмножество имен, которые не . Как объясняет документация:

Это то же самое, что и [n for n in names if fnmatch(n, pattern)], но реализовано более эффективно.

Итак, чтобы сделать наоборот, вы просто бросаете в not:

for ignore in ignore_files:
    filenames = [n for n in filenames if not fnmatch(n, ignore)]

Наконец, вы пытаетесь фильтровать частичные имена путей, а не только имена файлов, но вы не выполняете join до тех пор, пока не будет фильтрация. Итак, переключите порядок:

filenames = [os.path.join(root, filename) for filename in filenames]
for ignore in ignore_files:
    filenames = [n for n in filenames if not fnmatch(n, ignore)]
matches.extend(filenames)

Есть несколько способов улучшить это.

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

Кроме того, может быть и не проще понять, если вы инвертируете порядок циклов, например:

filenames = (n for n in filenames 
             if not any(fnmatch(n, ignore) for ignore in ignore_files))

Наконец, если вас беспокоит производительность, вы можете использовать fnmatch.translate для каждого выражения, чтобы превратить их в эквивалентные регулярные выражения, а затем объединить их в одно большое регулярное выражение и скомпилировать его, и использовать это вместо цикла вокруг fnmatch. Это может оказаться сложным, если ваши шаблоны могут быть более сложными, чем просто *.jpg, и я бы не рекомендовал его, если вы действительно не определяете узкое место производительности здесь. Но если вам нужно это сделать, я видел, по крайней мере, один вопрос о SO, где кто-то приложил много усилий, чтобы выбить все крайние случаи, поэтому поиск вместо того, чтобы пытаться написать его самостоятельно.

7
ответ дан abarnert 22 August 2018 в 07:02
поделиться
  • 1
    Большое вам спасибо, теперь это мой код (end-to-end): ignore_files = ['foo', ' / foo'] matches = [] для root, dirnames, filenames в os.walk ('. '): для имени файла в файле fnmatch.filter (filenames,' '): filename = os.path.join (root, filename) [2:] matches.append (имя файла) для ignore в ignore_files: matches_ = [ n для n в совпадениях, если не fnmatch.filter ([n], ignore)] может быть лучше? благодаря – fj123x 10 August 2014 в 19:01
  • 2
    @ fj123x: вы действительно не можете публиковать код в комментариях, потому что они едят все форматирование. Или отправьте новый вопрос, отредактируйте его в свой существующий вопрос или вставьте его где-нибудь, как pastebin.com , и разместите ссылку здесь. – abarnert 10 August 2014 в 20:21
  • 3
    @ fj123x: Но один быстрый комментарий: Нет причин для fnmatch.filter(filenames, '*'). Все имена файлов соответствуют *, поэтому просто возвращает копию filenames. – abarnert 10 August 2014 в 20:21
  • 4
    Это действительно не обрабатывает правила .gitignore , такие как **/a/b, a/b/** и a/**/b, и, похоже, не справляется с простым foo. Например, foo в .gitignore будет соответствовать foo и a/foo, но fnmatch не будет работать на a/foo – gman 17 July 2015 в 10:40
  • 5
    Да, кажется, не работает вообще , хотя, возможно, я что-то пропустил. – gman 17 July 2015 в 11:40
matches.extend([fn for fn if not filename in ignore_files])

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

def reject(filename, filter):
    """ Takes a filename and a filter to reject files that match."""
    if len(filter)==0:
         return False
    else:
         return fnmatch.fnmach(filename, filter[0]) or reject(filename, filter[1:])

matches.extend([os.path.join(root, fn) for fn in filenames if not reject(fn, ignore_files)])

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

Вы также можете попробовать что-то вроде:

filenames = set(filenames)  # convert to a set
for filter in ignore_files:
   filenames = filenames - set(fnmatch.filter(filenames, filter)) # remove the matches
matches.extend([os.path.join(root, fn) for fn in filenames])  # Add to matches
-1
ответ дан Steve Barnes 22 August 2018 в 07:02
поделиться
  • 1
    Только если ignore_files - список простых имен файлов, .gitignore и fnmatch разрешают шаблоны glob, и это чрезвычайно полезно. В OP есть пример (*.jpg). – user 10 August 2014 в 15:37
  • 2
    Неверным является имя - ignore_files, а не ignore_patterns – Steve Barnes 10 August 2014 в 16:02
  • 3
    Обратите внимание, что некоторые шаблоны соответствуют путям, а не только именам файлов. – Jason S 10 August 2014 в 16:20
  • 4
    можете ли вы объяснить использование match.extend ([fn для fn, если не отклонить (filename, ignore_files)])? вы не используете & quot; in & quot; в предложении, и какое имя файла было бы? благодаря – fj123x 10 August 2014 в 16:57
  • 5
    @ fj123x: Список listcomp отсутствует in filenames между for fn и if not. Вам нужно добавить его, чтобы сделать эту работу. Но, как отметил Делнан, это не сработает для вас. – abarnert 10 August 2014 в 17:53
Другие вопросы по тегам:

Похожие вопросы: