Chcę móc dopasować wzór w formacie glob
do listy łańcuchów, a nie do rzeczywistych plików w systemie plików. Czy jest jakiś sposób to zrobić, lub przekonwertować wzór glob
łatwo do regex?Python glob, ale z listą łańcuchów zamiast z systemem plików
Odpowiedz
Dobra kopia artysty; świetni artyści steal.
I stole;)
fnmatch.translate
przekłada globs ?
i *
do REGEX .
i .*
odpowiednio. Poprawiłem go, aby nie.
import re
def glob2re(pat):
"""Translate a shell PATTERN to a regular expression.
There is no way to quote meta-characters.
"""
i, n = 0, len(pat)
res = ''
while i < n:
c = pat[i]
i = i+1
if c == '*':
#res = res + '.*'
res = res + '[^/]*'
elif c == '?':
#res = res + '.'
res = res + '[^/]'
elif c == '[':
j = i
if j < n and pat[j] == '!':
j = j+1
if j < n and pat[j] == ']':
j = j+1
while j < n and pat[j] != ']':
j = j+1
if j >= n:
res = res + '\\['
else:
stuff = pat[i:j].replace('\\','\\\\')
i = j+1
if stuff[0] == '!':
stuff = '^' + stuff[1:]
elif stuff[0] == '^':
stuff = '\\' + stuff
res = '%s[%s]' % (res, stuff)
else:
res = res + re.escape(c)
return res + '\Z(?ms)'
Ten à la fnmatch.filter
zarówno re.match
i re.search
praca.
def glob_filter(names,pat):
return (name for name in names if re.match(glob2re(pat),name))
Wzorce globu i łańcuchy znalezione na tej stronie pomyślnie zaliczają test.
pat_dict = {
'a/b/*/f.txt': ['a/b/c/f.txt', 'a/b/q/f.txt', 'a/b/c/d/f.txt','a/b/c/d/e/f.txt'],
'/foo/bar/*': ['/foo/bar/baz', '/spam/eggs/baz', '/foo/bar/bar'],
'/*/bar/b*': ['/foo/bar/baz', '/foo/bar/bar'],
'/*/[be]*/b*': ['/foo/bar/baz', '/foo/bar/bar'],
'/foo*/bar': ['/foolicious/spamfantastic/bar', '/foolicious/bar']
}
for pat in pat_dict:
print('pattern :\t{}\nstrings :\t{}'.format(pat,pat_dict[pat]))
print('matched :\t{}\n'.format(list(glob_filter(pat_dict[pat],pat))))
bardzo wnikliwe - dzięki! –
Świetna miarka! Tak, tłumaczenie wzoru na taki, który ignoruje separatory ścieżek, jest świetnym pomysłem. Zauważ, że nie obsługuje on 'os.sep' lub' os.altsep', ale powinno to być łatwe do przystosowania. –
Dzięki @ martijn-pieters –
nieważne, znalazłem to. Chcę moduł fnmatch.
Oh wait - fnmatch nie obsługuje segmentacji ścieżek ... westchnienie: –
Czy możesz podać przykłady, w których 'fnmatch' nie obsługuje twojej sprawy? –
@BhargavRao:' glob.glob() 'stosuje wzory do elementów ścieżek separetely –
Podczas fnmatch.fnmatch
można stosować bezpośrednio w celu sprawdzenia, czy dany wzór pasuje do nazwy pliku lub nie, można również użyć metody fnmatch.translate
do generowania wyrażenia regularnego z danym fnmatch
wzoru:
>>> import fnmatch
>>> fnmatch.translate('*.txt')
'.*\\.txt\\Z(?ms)'
Z documenation:
fnmatch.translate(pattern)
Powrót wzór shell-styl przekształcony do zwykłego ś ssion.
Moduł glob
wykorzystuje fnmatch
module dla poszczególne elementy ścieżki.
Oznacza to, że ścieżka jest podzielona na nazwę katalogu i nazwę pliku, a jeśli nazwa katalogu zawiera znaki meta (zawiera wszelkie znaki [
, *
lub ?
) następnie są one rozbudowane rekurencyjnie.
Jeśli masz listę ciągów, które są proste nazwy plików, a potem po prostu stosując fnmatch.filter()
function wystarczy:
import fnmatch
matching = fnmatch.filter(filenames, pattern)
ale jeśli zawierają pełne ścieżki, trzeba wykonać więcej pracy jako wyrażenie regularne generowane robi nie uwzględnia segmentów ścieżek (symbole wieloznaczne nie wykluczają separatorów ani nie są dostosowane do dopasowywania ścieżek między platformami).
można skonstruować prosty trie z torów, a następnie dopasować wzór przeciwko temu:
import fnmatch
import glob
import os.path
from itertools import product
# Cross-Python dictionary views on the keys
if hasattr(dict, 'viewkeys'):
# Python 2
def _viewkeys(d):
return d.viewkeys()
else:
# Python 3
def _viewkeys(d):
return d.keys()
def _in_trie(trie, path):
"""Determine if path is completely in trie"""
current = trie
for elem in path:
try:
current = current[elem]
except KeyError:
return False
return None in current
def find_matching_paths(paths, pattern):
"""Produce a list of paths that match the pattern.
* paths is a list of strings representing filesystem paths
* pattern is a glob pattern as supported by the fnmatch module
"""
if os.altsep: # normalise
pattern = pattern.replace(os.altsep, os.sep)
pattern = pattern.split(os.sep)
# build a trie out of path elements; efficiently search on prefixes
path_trie = {}
for path in paths:
if os.altsep: # normalise
path = path.replace(os.altsep, os.sep)
_, path = os.path.splitdrive(path)
elems = path.split(os.sep)
current = path_trie
for elem in elems:
current = current.setdefault(elem, {})
current.setdefault(None, None) # sentinel
matching = []
current_level = [path_trie]
for subpattern in pattern:
if not glob.has_magic(subpattern):
# plain element, element must be in the trie or there are
# 0 matches
if not any(subpattern in d for d in current_level):
return []
matching.append([subpattern])
current_level = [d[subpattern] for d in current_level if subpattern in d]
else:
# match all next levels in the trie that match the pattern
matched_names = fnmatch.filter({k for d in current_level for k in d}, subpattern)
if not matched_names:
# nothing found
return []
matching.append(matched_names)
current_level = [d[n] for d in current_level for n in _viewkeys(d) & set(matched_names)]
return [os.sep.join(p) for p in product(*matching)
if _in_trie(path_trie, p)]
ten kęs można szybko znaleźć mecze używając globs dowolnym miejscu wzdłuż ścieżki:
>>> paths = ['/foo/bar/baz', '/spam/eggs/baz', '/foo/bar/bar']
>>> find_matching_paths(paths, '/foo/bar/*')
['/foo/bar/baz', '/foo/bar/bar']
>>> find_matching_paths(paths, '/*/bar/b*')
['/foo/bar/baz', '/foo/bar/bar']
>>> find_matching_paths(paths, '/*/[be]*/b*')
['/foo/bar/baz', '/foo/bar/bar', '/spam/eggs/baz']
W Pythonie 3.4+ możesz po prostu użyć PurePath.match
.
pathlib.PurePath(path_string).match(pattern)
na Python 3.3 lub wcześniej (w tym 2.x), dostać pathlib
from PyPI.
Należy pamiętać, że aby uzyskać wyniki niezależny od platformy (które zależą dlaczego używasz tego), że chcesz, aby wyraźnie stwierdzić PurePosixPath
lub PureWindowsPath
.
- 1. Python glob - pobierz najnowszy plik z listy
- 2. Python. Manipulacja z listą słowników
- 3. Jak wyśmiać os.walk w python z tymczasowym systemem plików?
- 4. z systemem plików binarnych ip323 z interaktywnej aplikacji z cygwin
- 5. Python: lista filtrów listy z inną listą
- 6. Rekursja python z listą zwraca Brak
- 7. Dlaczego wymagany jest ClassManifest z tablicą, ale nie z listą?
- 8. Rozwiązuj dowiązania symboliczne z systemem plików doładowania
- 9. Niezsynchronizowane źródło Eclipse z systemem plików
- 10. Python przetwarza tekst z wielu plików txt
- 11. glob nie rozpoznaje pliku z nawiasami kwadratowymi
- 12. Szybkie porównywanie ciągów z listą
- 13. Łączenie tabeli z listą
- 14. "Problem z listą oczekujących"
- 15. Flexbox z listą ul
- 16. upload plików z Python Mechanize
- 17. Najbardziej efektywny sposób tworzenia słownika Python z listą
- 18. Perforce P4v: Jak znaleźć plik z listą plików do znalezienia?
- 19. Django 1.4 - bulk_create z listą
- 20. glob() - Sortuj według nazwy
- 21. Mock java.io.File z systemem plików in-memory. Może JimFs
- 22. W jaki sposób można używać plików cookie z systemem Superagent?
- 23. Jak utworzyć plik z systemem plików doładowania bez jego otwierania?
- 24. Jak grep z listą słów
- 25. filtr django z listą wartości
- 26. Włącz rejestrowanie plików dla log4net z kodu zamiast z konfiguracji
- 27. Java 8 CompletableFuture.allOf (...) z kolekcją lub listą
- 28. Lista z listą do hierarchii
- 29. Siatka Kendo z wbudowaną edytowalną listą
- 30. Problemy z systemem Android Soundpool
Dlaczego, do cholery, jest to tak naprawdę odrzucane? – Stilgar
Czy możesz dodać więcej treści i kontekstu? Jak w oczekiwanym wyjściu dla fałszywego systemu plików –
Więc chcesz podać listę plików jako python 'list' do globu, zamiast pobierania z systemu plików? –