Re: Design- Frage: Excel Umrechnung 'F1:H2' --> (5,7,2,1)
Verfasst: Sonntag 25. Oktober 2015, 11:56
Hab es gerichtet & vereinfacht:
Code: Alles auswählen
import re
def compose(f, g):
def composed(x):
return f(g(x))
return composed
class ParsingError(Exception):
pass
class Parser:
def _parse(self, result, text):
raise NotImplementedError
def parse(self, text):
result, rest = self._parse([], text)
if rest:
raise ValueError('Found trailing string: {}'.format(rest))
else:
return result
def __add__(self, parser):
return Then(self, parser)
def __or__(self, parser):
return Either(self, parser)
class Bind(Parser):
def __init__(self, parser, function):
self.parser = parser
self.function = function
def _parse(self, result, text):
r, t = self.parser._parse([], text)
return self.function(r)._parse(result + r, t)
def bind_compose(f, g):
def bind_composed(parser):
return Bind(Bind(parser, g), f)
return bind_composed
class Return(Parser):
def __init__(self, value):
self.value = value
def _parse(self, result, text):
if self.value is not None:
return result + [self.value], text
else:
return result, text
class Then(Parser):
def __init__(self, first, second):
self.first = first
self.second = second
def _parse(self, result, text):
return self.second._parse(*self.first._parse(result, text))
class Either(Parser):
def __init__(self, first, second):
self.first = first
self.second = second
def _parse(self, result, text):
try:
return self.first._parse(result, text)
except ValueError:
return self.second._parse(result, text)
class Optional(Parser):
def __init__(self, parser):
self.parser = parser
def _parse(self, result, text):
try:
return self.parser._parse(result, text)
except ValueError:
return result, text
class RegexParser(Parser):
def __init__(self, pattern, name):
self.pattern = pattern
self.name = name
self.match = re.compile(pattern=pattern).match
def _parse(self, result, text):
match = self.match(text)
if match:
return (
result + [{self.name: match.group()}],
text[match.end():],
)
else:
raise ValueError('could not parse pattern "{}": {}'
.format(self.pattern, text))
##############################################################################
column = RegexParser(pattern='[A-Z]+', name='Column')
row = RegexParser(pattern='\d+', name='Row')
colon = RegexParser(pattern=':', name='Colon')
dollar = RegexParser(pattern='\$', name='Dollar')
def check_columns_are_monotonic(result):
result = iter(result)
for token in result:
if 'Column' in token:
start_column = token['Column']
break
for token in result:
if 'Column' in token:
end_column = token['Column']
break
else:
return Return(None)
if start_column > end_column:
raise ParsingError('Wrong order of column indices!')
else:
return Return(None)
def check_rows_are_monotonic(result):
result = iter(result)
for token in result:
if 'Row' in token:
start_row = int(token['Row'])
break
for token in result:
if 'Row' in token:
end_row = int(token['Row'])
break
else:
return Return(None)
if start_row > end_row:
raise ParsingError('Wrong order of row indices!')
else:
return Return(None)
EXCEL_ADDRESS = (
bind_compose(check_columns_are_monotonic, check_rows_are_monotonic)(
Optional(dollar)
+ column
+ Optional(dollar)
+ row
+ Optional(
colon
+ Optional(dollar)
+ column
+ Optional(dollar)
+ row))
|
Bind(
Optional(dollar)
+ column
+ colon
+ Optional(dollar)
+ column, check_columns_are_monotonic)
|
Bind(
Optional(dollar)
+ row
+ colon
+ Optional(dollar)
+ row, check_rows_are_monotonic)
)
def parse(addr):
return EXCEL_ADDRESS.parse(addr)
def show(addr):
import pprint
print(addr)
pprint.pprint(parse(addr))
print()
def main():
show('A1')
show('$A1')
show('A$1')
show('$A$1')
show('A1:G7')
show('$A$1:$G$7')
show('$A:$G')
show('1:1')
# show('2:1')
# show('$G1:$A1')
if __name__ == '__main__':
main()