Seite 1 von 1

minimales Markup nach HTML-Konverter

Verfasst: Sonntag 23. Juni 2013, 20:29
von noisefloor
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

Re: minimales Markup nach HTML-Konverter

Verfasst: Sonntag 23. Juni 2013, 20:35
von 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. :-)

Re: minimales Markup nach HTML-Konverter

Verfasst: Sonntag 23. Juni 2013, 21:15
von noisefloor
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

Re: minimales Markup nach HTML-Konverter

Verfasst: Montag 24. Juni 2013, 18:22
von jerch
Nur mal so als Hinweis:

Code: Alles auswählen

= <script>alert('Danke, dass Du meinen JS-Code ausführst.');</script>
;)

Re: minimales Markup nach HTML-Konverter

Verfasst: Montag 24. Juni 2013, 19:45
von Sirius3
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()))

Re: minimales Markup nach HTML-Konverter

Verfasst: Montag 24. Juni 2013, 19:58
von noisefloor
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