re-basierte Scanner-Klasse
Verfasst: Sonntag 1. März 2009, 11:51
Offenbar versteckt sich seit einigen Jahren eine Scanner-Klasse im re-Modul. Der Autor des zitierten Blog-Beitrags hat dennoch eine eigene Implementierung gebaut, das kann ich auch, dachte ich mir:
Mein Code ist ebenfalls nicht kompatibel, aber IMHO einfacher zu benutzen. Ich übergebe `Scanner` eine Liste von Tupeln. Die Methode `scan` liefert immer ein 2-Tupel mit dem Tokentyp und dem Wert zurück. Das Eingabetupel beginnt immer mit einem regulären Ausdruck. Folgt nichts weiter, sind Tokentyp und Wert gleich. Ansonsten ist der zweite Wert des Eingabetupels der Tokentyp. Ist dieser IGNORE, wird das Token ignoriert. Ein optionaler dritter Wert ist eine Funktion, die den Wert nochmal verarbeiten kann. Hier ein Beispiel für S-Ausdrücke:
Stefan
Code: Alles auswählen
class Scanner(object):
def __init__(self, *rules):
self.rules = rules
self.re = re.compile("|".join("(" + r[0] + ")" for r in rules))
def scan(self, s):
for m in self.re.finditer(s):
try:
rule = self.rules[m.lastindex - 1]
except IndexError:
yield 'ERROR', s[m.start():]
break
value = m.group()
token = rule[1] if len(rule) > 1 else value
if len(rule) > 2:
value = rule[2](value)
if token != 'IGNORE':
yield token, value
yield 'END', ''
Code: Alles auswählen
for t in Scanner(
(r'[()]',),
(r'\d+(?![^()\s])', 'int', int),
(r'[^()\s]+', 'sym',),
(r'\s+', 'IGNORE')
).scan("(a 1+ (c? 3))"):
print t