2013-06-09 12 views
6

Używam dateutil do parsowania nazw plików obrazu i sortowania według daty. Ponieważ nie wszystkie moje zdjęcia mają metadane, dateutil próbuje zgadnąć, gdzie je umieścić.Python parser dateutil, ignoruj ​​część kodu nie będącą datą

Większość moich zdjęć są w następującym formacie: 2007-09-10_0001.jpg 2007-09-10_0002.jpg etc ...

fileName = os.path.splitext(file)[0] 
print("Guesssing date from ", fileName) 
try: 
    dateString = dateParser.parse(file, fuzzy=True) 
    print("Guessed date", dateString) 
    year=dateString.year 
    month = dateString.month 
    day=dateString.day 
except ValueError: 
    print("Unable to determine date of ", file) 

Zwrot jestem coraz to:

('Guesssing date from ', '2007-09-10_00005') 
('Unable to determine date of ', '2007-09-10_00005.jpg') 

Teraz powinienem być w stanie oderwać wszystko od podkreślenia, ale chciałem, jeśli to możliwe, bardziej niezawodne rozwiązanie, na wypadek gdyby zdjęcia miały inny format. I choć niewyraźne próbowałbym znaleźć dowolną datę w łańcuchu i dopasować do tego, ale najwyraźniej nie działa ...

Czy istnieje prosty sposób, aby parser znaleźć coś, co wygląda jak data i przestać po tym? Jeśli nie, jaki jest najłatwiejszy sposób zmuszenia analizatora do ignorowania wszystkiego po podkreśleniu? Lub sposób definiowania wielu formatów daty z sekcjami ignorowania.

Dzięki!

+0

Czy data przynajmniej jakoś sformatowany? Na przykład "yyyy-mm-dd gdzieś w nazwie pliku"? – mishik

+0

Mam na myśli to, że czasami nie będziesz w stanie odróżnić miesiąca od daty, jeśli formatem daty jest rrrr-dd-mm lub rrrr-mm-dd. – mishik

+0

@mishik Tak, zwykle jest to coś w stylu "2007-09-10" w pełnej nazwie pliku "2007-09-10_001". Jeśli usunę "_001" z ciągu, to rozpozna datę dokładnie w porządku. – deranjer

Odpowiedz

4

Można próbować „zmniejszyć” ciąg tak długo, jak nie można zdekodować go:

from dateutil import parser 

def reduce_string(string): 
    i = len(string) - 1 
    while string[i] >= '0' and string[i] < '9': 
     i -= 1 
    while string[i] < '0' or string[i] > '9': 
     i -= 1 
    return string[:i + 1] 

def find_date(string): 
    while string: 
     try: 
      dateString = parser.parse(string, fuzzy=True) 
      year = dateString.year 
      month = dateString.month 
      day = dateString.day 
      return (year, month, day) 
     except ValueError: 
      pass 

     string = reduce_string(string) 

    return None 

date = find_date('2007-09-10_00005') 
if date: 
    print date 
else: 
    print "can't decode" 

Pomysł polega na usunięciu koniec łańcucha (dowolne numery następnie każda niezgodność numerów), aż parser może dekodować go do prawidłowej daty.

+0

Dzięki! Wygląda na to, że będzie to najlepsze rozwiązanie dla mnie, również dzięki za napisanie kodu. Bardzo nowy dla Pythona (i programowania) i zajęłoby mi to trochę czasu: D – deranjer

2

Komentowanie przyszłości tutaj, jako nieco więcej wglądu w ten problem.

O ile wyszukiwanie dateutil jest całkiem niezłe w wyszukiwaniu dat w normalnym języku naturalnym, kończy się niepowodzeniem w łańcuchach takich jak powyższy z tonami szumu związanego z liczbą/symbolem. Z nowszych wersjach dateutil jednak, gdy uruchomiony:

>>> from dateutil.parser import parse 
>>> parse('2007-09-10_00005.jpg', fuzzy=True) 

parse nie z TypeError: 'NoneType' object is not iterable, który nie jest bardzo idiomatyczne.

Inną alternatywą jest po prostu wyszukiwanie znanego formatu daty za pomocą wyrażeń regularnych. Oczywiście, to zależy od przypadku użycia, ale OP wspomniał, że jego termin był zawsze w formacie YYYY-MM-DD, co czyni go idealnym do wyszukiwania regex:

from dateutil.parser import parse 
import re 

date_pattern = re.compile('\d{4}-\d{2}-\d{2}') 

def extract_date(filename): 
    matches = re.match(date_pattern, filename) 
    if matches: 
     return parse(matches.group(0)) 
    else: 
     return None 

extract_date('2007-09-10_00005.jpg') # datetime.datetime(2007, 9, 10, 0, 0)