Suche Informationen über -- Text - lexer - parser --

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

EDIT:

Jack, wie gewohnt saubere Qualität!! :) -- *thumbs-upp*

Ich werde an meiner Version *trotzdem* weiter basteln :D

@EnTe: Ich würde BlackJacks Variante nehmen für euer vorhaben. Sieht sehr preformant und speicher schonend aus :) Meine wird wohl ein wenig Overkill, da ich gleich einen allgemeinen Markup=>AST=>X-Beliebiges Format-Generator schrieben werde (Bin schon ziemlich weit.), der auch BBC, reStr, etc in ein AST überführen kann. -- Also für euer vorhaben wird es wider zu groß denke ich.

lg
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Hmm, irgendwie verstehe ich nicht so ganz wie dein Lexer den Beginn- und End-Tag von Markups mit gleichen Token unterscheiden kann :? Bei mir musste ich dafür ein par Zeilen schreiben.

EDIT: Ups, hab ein Denkfehler gehabt. Ist für Markups ja garnicht notwendig. Wenn z.B. ein ohne endtag gefunden wurde, wird es ehe als plaintext interpretiert.
BlackJack

sape hat geschrieben:Hmm, irgendwie verstehe ich nicht so ganz wie dein Lexer den Beginn- und End-Tag von Markups mit gleichen Token unterscheiden kann :? Bei mir musste ich dafür ein par Zeilen schreiben.
Das kann mein Lexer auch nicht, das wird im HTML-Writer mit dem Stack gemacht.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Nun hab ichs verstanden, nach dem ich die Scource ein wenig länger durchgelesen habe. (Einige Sachen waren für mich nicht so offensichtlich.)

BTW: Die regexp von dir verstehe ich noch nicht. Müssen die so Kompliziert sein?

Ich hab das so gelöst mit de regexp (Kleiner Ausschnitt):

Code: Alles auswählen

[...]
from ast.ast import MarkupClassNames as MCN

_NAME_OF_THIS_MODULE = os.path.basename(__file__).split('.')[0]


class BasisLexer(object):[...]
    def __init__(self, source):
        self.markup_identifier = (
            # Markups die den gleichen Bezeichner für Begin und Ende verwenden.
            {MCN.MARKUP_BOLD:      (r'\*\*', None)}, # <- **
            {MCN.MARKUP_ITALIC:    (r'//', None)},
            {MCN.MARKUP_UNDERLINE: (r'__', None)},
            # Markups die unterschiedliche Bezeichner für Begin und Ende verwenden.
            {MCN.MARKUP_CODE:      (r'{{{', r'}}}')}
        )
        self.init(source)
        
    def init(self, source):
        mre = re.compile(self._merge_markups_to_restr())
        self.source = [x for x in mre.split(source) if x != '']
        self._lexer_stream = None
        [...]
        
    def _merge_markups_to_restr(self):
        li = list()
        for elem in self.markup_identifier:
            identifier = elem.values()[0]
            if identifier[1] is not None:
                li.append("%s|%s|" % (identifier[0], identifier[1]))
            else:
                li.append("%s|" % identifier[0])
        
        return r"(%s)" % "".join(li)[0:-1]

[...]
Das ergibt (\*\*|//|__|{{{|}}}). Damit splite ich den text. Ist das eventuell nicht ok? Welchen vorteil habe ich mit deinen regexp code? -- Bisher habe ich damit alles richtig gesplitet gekriegt ohne Fehler.

BTW: Falls gleich die fragen kommen wegen `` def init(self, source):``
Ganz Simpel: Jeder Lexer erbt nachher von ``BasisLexer`` und muss
``self.markup_identifier `` in ``__init__`` implementieren und darf nicht ``BasisLexer.__init__(...)`` aufrufen, sondern muss ``self.init(...)`` aufrufen. Den Rest erledigt die Klasse. Eventuell noch ein par Anpassungen (Falls der Lexer nicht genug kann)...
BlackJack

sape hat geschrieben:BTW: Die regexp von dir verstehe ich noch nicht. Müssen die so Kompliziert sein?

Ich hab das so gelöst mit de regexp (Kleiner Ausschnitt):

[…]

Das ergibt (\*\*|//|__|{{{|}}}). Damit splite ich den text. Ist das eventuell nicht ok? Welchen vorteil habe ich mit deinen regexp code? -- Bisher habe ich damit alles richtig gesplitet gekriegt ohne Fehler.
Das ist schon okay, erkennt aber weder Überschriften noch "Befehle mit Argumenten" wie ``#image[spam/eggs.png]``. Den ersten Teil habe ich genauso wie Du.
cracki
User
Beiträge: 72
Registriert: Montag 25. Dezember 2006, 05:01

blackjack:
nur eine frage. erkennt dein code auch geschachtelte tags, auch vom gleichen typ? oder z.b. auch nocode-tags?
...meh...
BlackJack

cracki hat geschrieben:blackjack:
nur eine frage. erkennt dein code auch geschachtelte tags, auch vom gleichen typ? oder z.b. auch nocode-tags?
Geschachtelte Tags ja, aber vom gleichen Typ? Wie soll das gehen und wozu soll das gut sein? Beispiel:

**foo**bar**baz**

Sollen da jetzt `foo` und `baz` fett sein, oder alles fett und `bar` doppelt fett, oder nur einfach fett, oder…?

Das hier: **foo__bar__baz** wird jedenfalls zu foobarbaz

Was sind `nocode`-Tags?
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

BlackJack hat geschrieben: Das ist schon okay, erkennt aber weder Überschriften noch "Befehle mit Argumenten" wie ``#image[spam/eggs.png]``. Den ersten Teil habe ich genauso wie Du.
Das kommt noch. Sind ja nur 3 zusätzliche Einträge in der Tabelle :)
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

BlackJack hat geschrieben: **foo**bar**baz**

Sollen da jetzt `foo` und `baz` fett sein, oder alles fett und `bar` doppelt fett, oder nur einfach fett, oder…?
Ganz simpel: ``foo`` und ``baz`` ist fett und bar nicht. Logisch! ->
**foo**
bar
**baz**

Alles andere wäre auch sehr komisch. Daher sehe ich inmoment auch nicht den Sinn drine.

Cracki, es wird ja immer vom ersten aufkommen von z.B. ``**`` bis zum nächsten aufkommen ausgewertet. Verschachtelungen gleichen Types sind garnicht möglich (Ohne Sonderreglung) und völlig Sinnfrei. Verschachtelungen anderen Typs sind mögcih, da bei BlackJacks Variante ein Stack zum Einsatzt kommt (Bei mir wird sowas schon im Lexer ausgewertet und der Strom dementsprechende angepasst.).


BlackJack ich glaube mit noncode meint er sowas(?):
** {{{ test }}} **

in BBC würde sowas daraus werden (Bold wird zwar ausgewertet (Tags werden nicht angezeigt), wirkt sich aber nicht auf code-tag aus.:

Code: Alles auswählen

 test 
[/b]

Also

Code: Alles auswählen

[b][code] test 
[/b][/code]
Da ist die Frage was EnTe in seiner Spezifikation vorgesehen hat.



Zumindest ist der umgekehrte Fall klar: {{{ ** test ** }}} =

Code: Alles auswählen

[b]test[/b]
Also

Code: Alles auswählen

[b]test[*b][*code] 
[i](*=/)[/i]

Das macht das, was auch EnTe vorgesehen hat.

lg
EnTeQuAk
User
Beiträge: 986
Registriert: Freitag 21. Juli 2006, 15:03
Wohnort: Berlin
Kontaktdaten:

Also Jungz! -- Super Arbeit! :)


Ich bin jetzt erstma ne ganze Woche in Cottbus, zu nem Seminar... leider ohne Lappi. Aber dannach werde ich eure Lösungen sehr gerne und mit viel Gewissen ausprobieren.


Ich wollte jedenfalls schonmal sehr großen Dank an BlackJack und sape und die anderen hier ausrichten! :)


MfG EnTeQuAk
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Hi. Hab nun nach ein wenig rumprobieren und lesen des Atikels bei wikipedia folgende RegExp für Commands. Die fügt sich gut in meinen Lexer ein und ist ziemlich flexibel.

r'(#link)([ \t]*)(\[{1})([^\[\].]+)(]{1})'

Damit sind folgende alle erlaubt:
#link[foobar]
#link [ foobar ]
#link [ssss]]]]] # Weitere ] am ende werden als Literal interpretiert.

Folgendes ist nicht erlaubt:
#link [[foobar]
#link foobar
#link [foobar
# link [foobar]
#link[]

Der Ausdruck ([ \t]*) lest sich z.B. durch ([\s]*) ersetzten und dann wäre es auch Zeilen unabhängig (fast)->

Code: Alles auswählen

#link
[ fobar]
Sowas kriege ich ncoh nicht hin:

Code: Alles auswählen

#link [
fobar
]

oder

#link
[
    foobar
]
Nun die Frage: Wie schnell ist die RegExp? Weil ich hab mir gedacht, da es flexibel ist, ein speziellen Tag in dem Lexer einzurichten, wo man Funktionsname, eine öffnende und schließende Klammer seiner Wahl angeben kann und dann die obere RegExp erzeugt wird :) -- Der Einfachheit halber, da es doch schon ziemlich gedauert (1 Stunde mit Tests) hat bis Ich so eine RegExp hingekriegt habe. Und das will ich nicht unbedingt jemande zumuten, wenn jemand später mein Script nutzt ;)

Ein wenig Info:

# (#link) = #link muss vorkommen
# ([ \t]*) = es dürfen nach #link beliebig viele Leerzeichen und tabs vorkommen
# (\[{1}) = es muss danach ein [ kommen und nur einmal!
# ([^\[\].]+) = es dürfen danach beliebige Zeichen kommen
# (]{1}) = es muss danach ein ] folgen. Danach sind weitere ] erlaubt!
# sie werden lediglich als laterale aufgefasst ;)

Code: Alles auswählen

    source = """
    #link [ fobar]
    
"""
    TAGS_RE = re.compile(r'(#link)([ \t]*)(\[{1})([^\[\].]+)(]{1})')
    tokens = [x for x in TAGS_RE.split(source) if x != '' and x != None]
    print tokens
    # ['\n    ', '#link', ' ', '[', ' fobar', ']', '\n    \n']
Würde mich über ein par Tipps freuen wie man RegExp auf Effizienz hin testet, da ich mit RegExp noch wenig Erfahrung habe.

lg
Benutzeravatar
Mr_Snede
User
Beiträge: 387
Registriert: Sonntag 8. Februar 2004, 16:02
Wohnort: D-Dorf, Bo

Hallo alle zusammen und vielen Dank für eure Hilfe vei unseren Problemen / Ideen zu dauCMS.

Unter:
http://www.daucms.de/dokumentation/index.html
ist zu sehen, was dauCMS im Moment kann. (oder eben auch nicht)

Ich verfolge diesen Thread aufmerksam, denn ich bin dabei Listen als Wikisyntax zu implementieren.
Für das Menü habe ich bis jetzt eine simple Schleife genommen.
Mein Ziel ist es einen Block zu schreiben, der sowohl das Menü generiert (halt eine Liste mit Links) als auch eine normale Liste innerhalb einer Textseite.

Ich schaue mal, wie sich meine Schleife dementsprechend aufbohren lässt. denke aber, dass ich über einer Rekursion recht elegant vorwärts komme. Wobei ich da dann schon wieder bei den Bäumen bin, die zu Anfang des Threads angesprochen wurden.

Code: Alles auswählen

#link [ 
fobar 
] 

oder 

#link 
[ 
    foobar 
]
oder

Code: Alles auswählen

#link 
[ fobar]
Müssen meiner Meinung gar nicht abgedeckt werden.

@ BlackJack:
Herzlichen Dank für deinen Code, an sowas wie den ElementTree habe ich wirklich nicht gedacht. Das was ich von deinem Code bis jetzt verstanden habe sieht schon sehr elegant aus.

Kann es sein, dass es unter Python2.5 (debian etch) den SimpleXMLWriter nicht gibt?

Code: Alles auswählen

mr_snede@pc-etch:~/div$ python2.5 ./dauparser_by_blacbird.py 
Traceback (most recent call last):
  File "./dauparser_by_blacbird.py", line 58, in <module>
    from elementtree.SimpleXMLWriter import XMLWriter
ImportError: No module named elementtree.SimpleXMLWriter
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hab ein paar Ideen für euer Markup: http://www.daucms.de/dokumentation/markup.html

Die Überschriften mit
= Überschrift =
== Überschrift ==

ist vielleicht noch ok. Wobei ich meine tinyTextile
h1. Überschrift
h2. Überschrift

besser finde, weil kein Endtag nötig ist und näher an HTML ran ist.

Die Links finde ich aber gar nicht gut! Ich meine, das ist ein wenig zu umständlich. OK, meine Links mit "LinxText":http://www.url.de ist auch nicht das wahre. Weil man dahinter keine Satzzeichen machen kann, die super tolle "Webseite":http://www.boa.de!!!
Da würde ich für das einfache moin Linktag pledieren: Ein super [http://www.boa.de Webseite]!!!
Aber warum muß man bei euch noch ein "#link" davor machen? Weil es auch ein "#image" gibt?

Bilder werden bei mit mit !/pics/bild.jpg! eingebunten. Vielleicht auch nicht optimal. Man könnte aber auch einfach [/pics/bild.jpg Ein Bild] machen und "Ein Bild" ist das "title"... Man muß dann allerdings den Link untersuchen, ob es eine URL ist, oder ein Bild. Aber das dürfte nicht schwer werden...

Was ist mit Listen??? Bei mir sehen die so aus:

Code: Alles auswählen

* 1. Eintrag in der erste Ebene
** 1. Unterprunkt in der zweiten Ebene
**** 1. Subunterpunkt in der vierter Ebene
**** 2. Subunterpunkt in der vierter Ebene
** 2. Unterprunkt in der zweiten Ebene


Nummerierte Liste:

# Nummer eins
# Nummer zweite
## und so...
## ...weiter...
Aber auch da könnte man vielleicht besser die moin Syntax nehmen.

Ich habe mir eh überlegt, evtl. mein tinyTextile Marup zu verbessern. Ich hab zwar einen Unitest, aber tinyTextile fällt da an ein paar Stellen durch. Es gibt Probleme bei Escaping/Codeblocks...

Die komplette tinyTextile Syntax: http://pylucid.org/index.py/TinyTextileExample/
Der Unitest: http://pylucid.net/trac/browser/trunk/t ... Textile.py

EDIT: Aber mal was anderes: Ob man nicht pygments dafür her nehmen kann um ein Markup zu schreiben???

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

sape hat geschrieben:Hi. Hab nun nach ein wenig rumprobieren und lesen des Atikels bei wikipedia folgende RegExp für Commands. Die fügt sich gut in meinen Lexer ein und ist ziemlich flexibel.

r'(#link)([ \t]*)(\[{1})([^\[\].]+)(]{1})'
Du machst zu viele unnötige Gruppierungen. Was Du hier am Ende einfach abfragen können möchtest, sind der "Befehl" (link), sofern es später verschiedene Befehle geben soll, und alles was zwischen den eckigen Klammern steht. Und den Gruppen würde ich dann auch Namen verpassen, das macht den Zugriff einfacher und das Programm verständlicher.

Die "Mengenangabe" ``{1}`` kannst Du weglassen. Der Ausdruck "x" sagt "ein `x`", der Ausdruck "x{1}" sagt "ein `x` nur einmal". Das ist redundant.

Und bei ``([^\[\].]+)`` bin ich mir nicht so ganz sicher warum Du ``[`` verbietest und ziemlich sicher das Du eigentlich keine Punkte verbieten willst.
BlackJack

Mr_Snede hat geschrieben:Kann es sein, dass es unter Python2.5 (debian etch) den SimpleXMLWriter nicht gibt?
Wenn man ihn nicht installiert, dann nicht. :-)
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

BlackJack, danke für das Feedback und die Tipps.

lg

EDIT:
BlackJack hat geschrieben:
Mr_Snede hat geschrieben:Kann es sein, dass es unter Python2.5 (debian etch) den SimpleXMLWriter nicht gibt?
Wenn man ihn nicht installiert, dann nicht. :-)
What? Unter Windows wird das bei dem Python2.5 Binary mit dabei.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

sape hat geschrieben:
BlackJack hat geschrieben:
Mr_Snede hat geschrieben:Kann es sein, dass es unter Python2.5 (debian etch) den SimpleXMLWriter nicht gibt?
Wenn man ihn nicht installiert, dann nicht. :-)
What? Unter Windows wird das bei dem Python2.5 Binary mit dabei.
Komisch, ich kann mich auch nicht erinnern, dass der jemals bei Python mitgeliefert wurde.

Habe auch Belege dafür. Vielleicht wird der Rest von ElementTree auch noch aufgenommen, aber erst später (also nicht in Python 2.5) - wie Effbot selbst sagt.

Und dass SimpleXMLWriter in Python 2.5 für Windows dabei ist, scheint mir aber auch recht seltsam zu sein, wenn MvL meint, dass der nicht dabei ist. Schließlich baut er ja die Windows-Builds, wenn ich richtig informiert bin.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
Mr_Snede
User
Beiträge: 387
Registriert: Sonntag 8. Februar 2004, 16:02
Wohnort: D-Dorf, Bo

Bei debian Etch ist in Python2.5 folgendes enthalten.

Code: Alles auswählen

/usr/lib/python2.5/xml/etree/ElementInclude.py
/usr/lib/python2.5/xml/etree/ElementPath.py
/usr/lib/python2.5/xml/etree/ElementTree.py
/usr/lib/python2.5/xml/etree/__init__.py
/usr/lib/python2.5/xml/etree/cElementTree.py
Ich dachte SimpleXMLWriter wäre ein Bestandteil von elementtree :

Code: Alles auswählen

ImportError: No module named elementtree.SimpleXMLWriter
@ Jens
Die Überschriften in "=" einzubetten, wird in vielen Wikiengines verwendet (moin, dokuwiki, trac, ...) ich finde es auch recht Bildhaft.
h1. Überschrift
h2. Überschrift
Ist mir zu nahe an einer wirklichen Programmiersprache das gefält mir als Wikisyntax nicht.

Listen sind bis jetzt wie in Moin(oder Dokuwiki, nur das hier eine Einrückungsebene aus 2 Leerzeichen besteht) geplant:

Code: Alles auswählen

 * tolle Liste
  * super Unterpunkt
  * noch besserer Unterpunkt
   * weil richtig weit eingerückt, der beste Unterpunkt
 * bla
 * blub
Wobei ich beim Schreiben der dauCMS Doku festgestellt habe, dass der Spiegelstrich anstelle des Asterix im Wikitext viel besser aussieht.
Aber es ist ja kein Problem beides zu implementieren.

Die Aktuelle Linksyntax entstammt Entes ersten Versuchen.Wir haben schon gesprochen die Syntax gegen die von moin auszutauschen. Da Ente aber diese Syntax schon umgesetzt hatte und wir gerne so weit kommen wollten, mit dauCMS Seiten zu erstellen, haben wir es vorerst dabei gelassen.
Also geplant ist etwas in diese Richtung:

Code: Alles auswählen

[http://www.python-forum.de/posting.php das deutsche Pythonforum] 
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Mr_Snede hat geschrieben:
h1. Überschrift
h2. Überschrift
Ist mir zu nahe an einer wirklichen Programmiersprache das gefält mir als Wikisyntax nicht.
Textile macht das genau so.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
Mr_Snede
User
Beiträge: 387
Registriert: Sonntag 8. Februar 2004, 16:02
Wohnort: D-Dorf, Bo

Leonidas hat geschrieben:
Mr_Snede hat geschrieben:
h1. Überschrift
h2. Überschrift
Ist mir zu nahe an einer wirklichen Programmiersprache das gefält mir als Wikisyntax nicht.
Textile macht das genau so.
Daher der Vorschlag vom Jens
Jens hat geschrieben:Die komplette tinyTextile Syntax: http://pylucid.org/index.py/TinyTextileExample/
Aber ehrlich gesagt finde ich die Textile Syntax zum Schreiben und Lesen mehr als sperrig.
Aber ich werde mal seinen Code für die Listen anschauen.

@ Jens
Du hattest ja schon früher mal eine Zusammenarbeit vorgeschlagen.
Ich denke so langsam haben Ente und ich uns in einige Themen eingearbeitet. Womit wir auch wirklich was beitragen könnten.

Zumindest beim Lexer / Parser könnten wir uns mal zusammensetzen.
Einen Kern, der unterschiedliche Wikisyntax parsen kann, wäre schon toll. Sozusagen Syntaxplugins.

So nu gehts aber ab inne Poofe sonst bin ich morgen schon wieder übermüdet :-(
Antworten