diff --git a/src/diana/sgfParser/property.py b/src/diana/sgfParser/property.py --- a/src/diana/sgfParser/property.py +++ b/src/diana/sgfParser/property.py @@ -1,4 +1,5 @@ import re +from datetime import date import logging as log from .propValues import choose, singleton, listOf, compose, number, real, double, color, text, empty, anything, point, move, stone @@ -8,6 +9,10 @@ GAME_INFO=1 UNKNOWN=99 +class DateException(Exception): + pass + + class Property: identRegexp=re.compile(r"[A-Z]+") @@ -32,6 +37,8 @@ class Property: i,x=choose(listOf(anything), singleton(anything))(s,i) res.name="_"+res.name res.value=x + if res.name=="DT": + res=DateProperty(x) i=skipWhitespace(s,i) return (i,res) @@ -46,8 +53,7 @@ class Property: if name in Property.patterns: return Property.patterns[name](s,start) else: - # !! raise or log or ignore - # print('warning, unknown property "{0}" at position {1}'.format(name,start)) + log.info("unknown property %s at position %d",name,start) return choose(listOf(anything), singleton(anything))(s,start) @property @@ -63,8 +69,9 @@ class Property: return res def __str__(self): + name=self.name.lstrip("_") val="[{0}]".format(self.value) if not isinstance(self.value,list) else "".join("[{0}]".format(x) for x in self.value) - return "{0}{1}".format(self.name,val) + return "{0}{1}".format(name,val) patterns={ "B":singleton(move), @@ -139,4 +146,42 @@ class Property: } -# !! TODO: date +class DateProperty(Property): + def __init__(self,value): + super().__init__() + self.name="DT" + self.value=[] + self.rawValue=value + self.parse(value) + + def parse(self,s): + regexp=re.compile(r"\d{4}(-\d\d){0,2}(,(\d{4}(-\d\d){0,2}|\d\d(-\d\d)?))*") + match=re.search(regexp,s) + if not match: + raise DateException('Could not parse a DT value: "{0}"'.format(s)) + substr=match.group(0) + dateStrs=substr.split(",") + dates=[] + prevFormat=None + + for s in dateStrs: + try: + (prevFormat,d)=DateProperty.parseSingle(s,prevFormat,dates[-1] if dates else None) + except ValueError: + raise DateException('Could not parse a DT value: "{0}"'.format(s)) + dates.append(d) + self.value=dates + + @staticmethod + def parseSingle(dateStr,prevFormat,prev=None): + tokens=dateStr.split("-") + num_tokens=list(map(int,tokens)) + if len(tokens)==3: + return ("YMD",date(*num_tokens)) + elif len(tokens)==2: + if len(tokens[0])==4: return ("YM",date(*num_tokens,1)) + else: return ("MD",date(prev.year,*num_tokens)) + else: + if len(tokens[0])==4: return ("Y",date(*num_tokens,1,1)) + elif prevFormat in ("YM","M"): return ("M",date(prev.year,*num_tokens,1)) + else: return ("D",date(prev.year,prev.month,*num_tokens))