minimales Markup nach HTML-Konverter

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.
Antworten
Benutzeravatar
noisefloor
User
Beiträge: 4258
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

ich brauche für ein Projekt eine sehr simples Markup, welches dann nach HTML konvertiert wird. Aus diversen Gründen dürfen keine externen Abhängigkeiten da sein, also fält Markdown & Co aus.

Das Markup soll "nur" folgende können:
  • Überschriften 1., 2. + 3. Ebene
  • unnummerierte Listen, nur eine Ebene (=unverschachtelt)
  • Kommentare im Ausgangstext, welche beim Konvertieren nach HTML "überlesen" werden
Mehr nicht. Mein 1. Ansatz sieht so aus:

Code: Alles auswählen

#!/usr/bin/env python

html = []
in_list = False

with open('test.tpl') as f:
    for line in f.readlines():
        if not line.startswith(' * ') and in_list:
            html.append('</ul>')
            in_list = False
        if line.startswith('#') or len(line.strip()) == 0:
            pass
        elif line.startswith('==='):
            line = line.strip('===')
            line = line.strip()
            html.append('<h3>{0}</h3>'.format(line))
        elif line.startswith('=='):
            line = line.strip('==')
            line = line.strip()
            html.append('<h2>{0}</h2>'.format(line))
        elif line.startswith('='):
            line = line.strip('=')
            line = line.strip()
            html.append('<h1>{0}</h1>'.format(line))
        elif line.startswith(' * '):
            if not in_list:
                html.append('<ul>')
                in_list = True
            line = line.strip(' * ')
            line = line.strip()
            html.append('<li>{0}</li>'.format(line))            
        else:
            line = line.strip()
            html.append('<p>{0}</p>'.format(line))
if in_list:
    html.append('</ul>')
output = '\n'.join(html)
print output
Was auch funktioniert, z.B. mit "test.tpl":

Code: Alles auswählen

Hallo Welt
#Kommentar
Abschnitt
=Header 1
==    Header 2
Abschnitt 2
=== Header 3
 * foo
 * bar
 * spam
 Es wurde nix gefunden.
 == falscher header?

nach der Leerzeile
Die Eingabedatei hat höchsten ein paar hundert Zeilen.

Frage: ist das mit den ganzen if / elif bei sowas der richtige Weg? Oder geht das eleganter / besser / robuster / ...
Bin, was diesen "Markup-Parser" (na ja, Pseudo-Parser...) angeht gerade ein wenig ideenlos.

Gruß, noisefloor
BlackJack

@noisefloor: Auf jeden Fall solltest Du noch mal nachlesen was `strip()` macht. Das sieht nicht so aus als wenn Du das richtig verstanden hast. :-)
Benutzeravatar
noisefloor
User
Beiträge: 4258
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
BlackJack hat geschrieben:@noisefloor: Auf jeden Fall solltest Du noch mal nachlesen was `strip()` macht. Das sieht nicht so aus als wenn Du das richtig verstanden hast. :-)
Ok - wenn das alles ist, dann bin ich zufrieden ;-)

Gruß, noisefloor
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Nur mal so als Hinweis:

Code: Alles auswählen

= <script>alert('Danke, dass Du meinen JS-Code ausführst.');</script>
;)
Sirius3
User
Beiträge: 18335
Registriert: Sonntag 21. Oktober 2012, 17:20

noisefloor hat geschrieben:Ok - wenn das alles ist, dann bin ich zufrieden
Zu viel Code-Duplizierungen.

Code: Alles auswählen

import re
MARKUP = {
  r"#": (None,lambda:''),
  r'([^=#*].*?)\s*$': ('', lambda txt:"<p>%s</p>"%txt),
  r"(=+)\s*(.*?)\s*$": ('', lambda eq,txt:"<h{0}>{1}</h{0}>".format(len(eq),txt)),
  r'\*\s*(.*?)\s*$': ('ul', lambda txt:"<li>%s</li>"%txt),
}

def generate_html(iterable):
    current_enclosing_tag = ""
    for line in iterable:
        for expr, (enclosing_tag, func) in MARKUP.iteritems():
            mtch = re.match(expr, line)
            if mtch:
                if enclosing_tag is not None and current_enclosing_tag!=enclosing_tag:
                    if current_enclosing_tag:
                        yield '</%s>'%current_enclosing_tag
                    if enclosing_tag:
                        yield '<%s>'%enclosing_tag
                    current_enclosing_tag=enclosing_tag
                yield func(*mtch.groups())
    if current_enclosing_tag:
        yield '</%s>'%current_enclosing_tag

if __name__=='__main__':
    print '\n'.join(generate_html("""Hallo Welt
#Kommentar
Abschnitt
=Header 1
==    Header 2
Abschnitt 2
=== Header 3
* foo
* bar
* spam
Es wurde nix gefunden.
== falscher header?

nach der Leerzeile""".splitlines()))
Benutzeravatar
noisefloor
User
Beiträge: 4258
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

@jerch: Yup, das stimmt. Für den "öffentlichen Betrieb" hätte das Skript aber IMHO noch mehr Schwächen. Was ist eingangs nicht gesagt habe: Das Skript wird später nur vom dem Nutzer ausgeführt, der auch das Template dafür schreibt. Von daher ist es ok, dass das Template auch HTML-Tags enthalten kann.

@Sirius3: "Zu viel Code-Duplizierungen." -> das war auch mein "Gefühl". Denn Einsatz des re-Moduls hatte ich auch im Sinn - besonders bei den `<hX>` Tags. Schaue mir deine Code später mal an, Danke schon mal!

Gruß, noisefloor
Antworten