Aus den Ideen von BlackJack und sape ging ein sehr simpler Parser hervor. Laut meinem Teamkollegen Mr_Snede ein sog. SAX-Parser (was auch immer das heißt )
Nun gut. Wie sieht der aus?
So:
ACHTUNG: Dies ist eine veraltete Version. Die neueste Version wird auf den letzten Seiten beschrieben!
Code: Alles auswählen
#!/usr/bin/env python
#-*- coding: utf-8 -*-
'''simple lexer/parser
'''
import re, string
class SyntaxParser(object):
"""
Syntaxparser and Lexer
All formatting commands can be parsed one line at a time, though
some state is carried over between lines.
"""
def __init__(self):
# that's the var that's needed to set a status
# so that nested tags can be better parsed
self.is_ = 0
self.in_noparse = 0
def _bold_replacer(self, match):
'''
replacer for **bold text***
'''
self.is_ = not self.is_
return ['</b>', '<b>'][self.is_]
def _underline_replacer(self, match):
'''
replacer for __underlined__ Text
'''
self.is_ = not self.is_
return ['</u>', '<u>'][self.is_]
def _italic_replacer(self, match):
'''
replacer for // italic text //
'''
self.is_ = not self.is_
return ['</i>', '<i>'][self.is_]
def _headline_replacer(self, match_d):
''' replacer function for == headlines == '''
match = re.compile('(?P<hlevel>={1,6})(.*)(?P=hlevel)').match(match_d)
if match:
level = len(match.group('hlevel'))
return '<h%d>%s</h%d>' % (level, match.group(2).strip(), level)
else:
return match_d
def _url_replacer(self, match):
'''
replacer for URL's in the text
'''
return '<a href="%s">%s</a>' % (match, match)
def _email_replacer(self, match):
'''
replacer for emails like 'da@dada.xy'
'''
return '<a href="mailto:%s">%s</a>' % (match, match)
def _br_replacer(self, match):
'''
replacer for breaks
'''
return '\n<br />'
def _noparse_replacer(self, match):
'''
implement a 'noparse'-Syntax...
it's like the [code]
'''
if match == '{{{' and not self.in_noparse:
self.in_noparse = 1
return '<pre class="noparse>"'
elif self.in_noparse and match == '}}}':
self.in_noparse = 0
return '</pre>'
else:
return match
def lex(self, raw):
'''
this function is the main-function, that let
the parser work.
it scans the text('raw') against 'scan_re'
and calls the 'replacer'-functions
'''
scan_re = re.compile(
r"("
+ r"(?P<br>\[\[BR\]\])"
+ r"|(?P<noparse>(\{\{\{|\}\}\}))"
+ r"|(?P<bold>\*\*)"
+ r"|(?P<italic>\/\/)"
+ r"|(?P<underline>__)"
+ r"|(?P<headline>(?P<hlevel>={1,6})(.*)(?P=hlevel))"
+ r"|(?P<url>(http|ftp|nntp|news|mailtoaim|icq|telnet|sftp|sip)\:[^\s'\"]+\S)"
+ r"|(?P<email>[-\w._+]+\@[\w.-]+)"
+ r")")
blank_re = re.compile("^\s*$")
eol_re = re.compile(r'\r?\n')
raw = string.expandtabs(raw)
indent_re = re.compile("^\s*")
for line in eol_re.split(raw):
if blank_re.match(line):
yield '<br />'
continue
yield re.sub(scan_re, self.parse, line)
if self.in_noparse: yield '</div>'
def parse(self, match):
'''
this function calls the 'replacer'-function wich
returns the replaced content
'''
for type, hit in match.groupdict().items():
if hit:
if self.in_noparse:
return apply(getattr(self, '_noparse_replacer'), (hit,))
else:
return apply(getattr(self, '_' + type + '_replacer'), (hit,))
else:
raise "Can't handle match %s" % match
def main():
txt = '''**__underlined bold__bold //italic//**
ente@gfx-united.de
http://dadada.xy
{{{
nicht getroffen: __ dadad ** dadada** __ }}}
= Überschrift erster Stufe = (die größte)
== Überschrift zweiter Stufe ==
=== Überschrift dritter Stufe === [[BR]]
==== Überschrift vierter Stufe ====
===== Überschrift fünfter Stufe =====
====== Überschrift sechster Stufe ====== (die kleinste)'''
da = SyntaxParser()
new = da.lex(txt)
for line in new:
print line
if __name__ == '__main__':
main()
[/code]
Wie funktioniert der?
Wie folgt:
Es gibt einen Text
Code: Alles auswählen
def main():
txt = '''**__underlined bold__bold //italic//**
ente@gfx-united.de
http://dadada.xy
'''
#[...]
Code: Alles auswählen
da = SyntaxParser()
new = da.lex(txt)
Code: Alles auswählen
for line in new:
print line
Jaa... das Innere ist ansich recht einfach gestrickt.
Es gibt eine Funktion 'lex()', die sozusagen das "Gehrin" bildet.
in Ihr wird die Variable '' scan_re '' definiert. Diese definiert die Regular Expressions, die später beim ersten scannen in Tokens zerlegt werden und direkt anhand der regex-gruppen auf die 'replacer'-Funktionen verteilt werden. D.H., das jede Regex in der Theorie eine Funktion besitzt, die sie bearbeitet.
Diese Funktion gibt dann den ersetzten String zurück.
Was sie dafür macht... bleibt ihr überlassen... Hier ist der Parser sehr flexibel.
Das ganze wird dann im Enddefekt als Generatorobjekt zurückgegeben.
Im großen und ganzen eine recht flexible Angelegenheit.
Ein Struktugramm, wie der Parser genau arbeitet ist in Arbeit und wird evtl. morgen fertiggestellt.
Ich freue mich über Feedback!
MfG EnTeQuAk