import std.html;
import std.alloc;
import std.string;
fn main(): int64 {
var o: pchar := alloc(512) as pchar;
Escape("Tom & Jerry's"c, o);
PrintLn(StrConcat("Escape: ", o));
var back: pchar := alloc(512) as pchar;
Unescape(o, back);
PrintLn(StrConcat("Rueckweg: ", back));
// Einzelne Entities durch den Dekoder
Unescape("& < > " ' ' A &unknown;"c, o);
PrintLn(StrConcat("Entities: ", o));
// UTF-8: 'à' ist C3 A0 - das zweite Byte ist 160
Escape("Caf\xc3\xa0 Grand-M\xc3\xa8re"c, o);
PrintLn(StrConcat("UTF-8: ", o));
return 0;
}
Escape: <a href="x">Tom & Jerry's</a>
Rueckweg: Tom & Jerry's
Entities: & < > " ' ' A M-BM- &unknown;
UTF-8: CafM-CM- Grand-MM-CM-(re
Die letzte Zeile ist durch ''cat -v'' sichtbar gemacht: ''M-C'' steht für das Byte 0xC3, ''M-'' + Leerzeichen für 0xA0. ''à'' (C3 A0) und ''è'' (C3 A8) kommen beide unversehrt durch — die frühere Latin-1-Regel „Byte 160 → '' ''" ist weg (#1419). Der Rückweg löst inzwischen **alle** Entities auf, ein unbekanntes ''&unknown;'' bleibt stehen. Gemessen mit 1.1.14A; ältere Fassungen dieser Seite zeigen die halb zerlegte Ausgabe.
import std.html;
import std.alloc;
import std.string;
fn J(b: bool): pchar { if (b) { return "ja"; } return "nein"; }
fn main(): int64 {
var o: pchar := alloc(512) as pchar;
// Tag-Analyse
GetTagName(""c, o); PrintLn(StrConcat("GetTagName(''): ", o));
GetTagName(""c, o); PrintLn(StrConcat("GetTagName(''): ", o));
GetTagName("
"c, o); PrintLn(StrConcat("GetTagName('
'): ", o));
PrintLn(StrConcat("IsClosingTag(''): ", J(IsClosingTag(""c))));
PrintLn(StrConcat("IsSelfClosing('
'):", J(IsSelfClosing("
"c))));
PrintLn(StrConcat("IsSelfClosing('
'): ", J(IsSelfClosing("
"c))));
PrintLn(StrConcat("HasTags('a < b'): ", J(HasTags("a < b"c))));
PrintLn(StrConcat("NeedsEscape('a & b'): ", J(NeedsEscape("a & b"c))));
// Verschachtelung
PrintLn(StrConcat("Balance('x
'): ", IntToStr(ValidateBalance("x
"c))));
PrintLn(StrConcat("Balance('x
'): ", IntToStr(ValidateBalance("x
"c))));
PrintLn(StrConcat("Balance('a
b
'): ", IntToStr(ValidateBalance("a
b
"c))));
PrintLn(StrConcat("Balance('
'): ", IntToStr(ValidateBalance("
"c))));
PrintLn(StrConcat("Balance('5 < 7 und 9 > 2'): ", IntToStr(ValidateBalance("5 < 7 und 9 > 2"c))));
// StripTags
StripTags("Hallo Welt
"c, o); PrintLn(StrConcat("Strip normal: ", o));
StripTags(""c, o); PrintLn(StrConcat("Strip script: ", o));
StripTags("5 < 7 und 9 > 2"c, o); PrintLn(StrConcat("Strip Text: ", o));
StripTags("Text
"c, o); PrintLn(StrConcat("Strip Attribut:", o));
// URL-Leerzeichen
EncodeSpaces("a b c"c, o); PrintLn(StrConcat("EncodeSpaces('a b c'): ", o));
DecodeSpaces(o, o); PrintLn(StrConcat("DecodeSpaces zurueck: ", o));
return 0;
}
GetTagName(''): div
GetTagName(''): span
GetTagName('
'): br
IsClosingTag(''): ja
IsSelfClosing('
'):ja
IsSelfClosing('
'): nein
HasTags('a < b'): ja
NeedsEscape('a & b'): ja
Balance('x
'): 0
Balance('x
'): 1
Balance('a
b
'): 0
Balance('
'): 0
Balance('5 < 7 und 9 > 2'): 0
Strip normal: Hallo Welt
Strip script: alert(1)
Strip Text: 5 2
Strip Attribut:Text
EncodeSpaces('a b c'): a+b+c
DecodeSpaces zurueck: a b c
> **''ValidateBalance'' unterscheidet Markup und Text** ([[https://github.com/SEOLizer/LyX-Compiler/issues/1420|#1420]], nachgemessen mit lyxc 1.2.2B):
>
> * ''%%a
b
%%'' → **0** (ausgeglichen): Void-Elemente zählen nicht als offen.
> * ''%%3 < 5
%%'' → **0**: ein ''<'' im Fließtext zählt nicht mit.
> * ''%%a%%'' → **1**: der fehlende Schluss-Tag wird gemeldet.
>
> Frühere Fassungen zählten jedes ''<'' als geöffnet, unabhängig davon, ob überhaupt ein Tag vorlag.
----
===== Tags entfernen =====
''StripTags'' kopiert alles, was außerhalb von ''<…>'' steht. Das Verfahren ist bewusst einfach — und hat zwei Folgen, die man kennen muss:
* **Der Inhalt bleibt.** Ein ''<script>''-Block verliert seine Tags, der Code darin steht anschließend im Text.
* **Ein ''<'' im Text frisst mit.** Aus ''5 < 7 und 9 > 2'' wird ''5 2'' — alles zwischen ''<'' und dem nächsten ''>'' gilt als Tag. Wer Text mit Vergleichszeichen verarbeitet, maskiert ihn vorher mit ''Escape''.
Für die Textextraktion aus wohlgeformtem HTML — der eigentliche Zweck — arbeitet die Funktion zuverlässig.
----
===== Leerzeichen für Formularparameter =====
^ Signatur ^ Beschreibung ^
| ''EncodeSpaces(input: pchar, output: pchar): int64'' | Ersetzt Leerzeichen durch ''+''. |
| ''DecodeSpaces(input: pchar, output: pchar): int64'' | Ersetzt ''+'' durch Leerzeichen. |
> **Das ist ''+'', nicht ''%%%20%%''.** Frühere Fassungen dieser Seite sprachen von „''%%%20%%'' für URLs" — tatsächlich erzeugt ''EncodeSpaces'' die Form aus ''application/x-www-form-urlencoded'', wie sie in Formulardaten und Abfrageparametern üblich ist. ''DecodeSpaces'' kennt umgekehrt nur ''+'' und lässt ''%%%20%%'' unverändert stehen.
>
> Beide Funktionen behandeln **ausschließlich das Leerzeichen**. ''&'', ''='', ''?'', ''#'' und Nicht-ASCII bleiben unangetastet — für vollständige URL-Kodierung ist ''std.net.http'' zuständig.
----
===== Fallstricke =====
* **Ausgabepuffer selbst anlegen und großzügig bemessen** — keine Funktion prüft die Zielgröße. Für ''Escape'' sind sechs Byte je Eingabezeichen sicher.
* **''Unescape'' löst benannte und numerische Entities auf** (#1418 behoben).
* **''Escape'' lässt UTF-8 unangetastet** (#1419 behoben).
* **Doppelte Maskierung** merkt niemand: ''%%Escape(Escape(x))%%'' ergibt ''<'' statt ''<''. Nur einmal maskieren, unmittelbar vor der Ausgabe.
* **Kein Dokumentmodell.** ''GetTagName'' und Verwandte erwarten einen Text, der **am** ''<'' beginnt; einen Tag-Iterator gibt es nicht. Wer Struktur braucht, nimmt [[lyx_-_programmiersprache:units:xml|std.xml]].
* **Kommentare, CDATA und Skriptinhalte** kennt die Unit nicht — ''<!-- a > b -->'' endet für ''StripTags'' beim ersten ''>''.
* Die exportierten Entity-Konstanten sind unit-privat; von außen sichtbar sind nur die elf Funktionen.
----
**Weiterführend:** [[lyx_-_programmiersprache:units:xml|std.xml — Parser mit Dokumentmodell]] · [[lyx_-_programmiersprache:units:string|std.string]] · [[lyx_-_programmiersprache:units:net:http|std.net.http]] · [[lyx_-_programmiersprache:units|Standard Library]]
**Quelle:** ''std/html.lyx'' (459 Zeilen) · **Autor:** Andreas Röne · **Copyright:** 2024–2025 Andreas Röne
Letzte Aktualisierung: 2026-09-05 ([[https://github.com/SEOLizer/LyX-Compiler/issues/1420|#1420]], nachgemessen mit lyxc 1.2.2B) — ''ValidateBalance''-Kasten auf den behobenen Stand gezogen.
Vorherige letzte Aktualisierung: 2026-08-13 — Seite gegen ''std/html.lyx'' überarbeitet: leere Konstanten-Tabelle entfernt, zwei lauffähige Beispiele mit echter Ausgabe, Entity-Tabelle, Fallstricke. Die Nennung als Mittel zur „HTML-Sanitisierung (XSS-Schutz)" ist gestrichen — ''StripTags'' entfernt Tags, nicht deren Inhalt. Belegt und als Issue erfasst: ''Unescape'' erkennt nur ''"'' ([[https://github.com/SEOLizer/LyX-Compiler/issues/1418|#1418]]), ''Escape'' zerstört UTF-8-Zeichen mit Folgebyte 0xA0 ([[https://github.com/SEOLizer/LyX-Compiler/issues/1419|#1419]]), ''ValidateBalance'' zählt Void-Elemente und Text-Kleinerzeichen mit ([[https://github.com/SEOLizer/LyX-Compiler/issues/1420|#1420]]). ''EncodeSpaces'' erzeugt ''+'', nicht ''%%%20%%''. Geprüft mit ''lyxc 1.0.21A''.
Codebeispiele geprüft: gegen **lyxc 1.2.5C** übersetzt (Prüflauf 2026-09-08 über die gesamte Doku: 574 Vollprogramme, 0 echte Fehler; zusätzlich 5159 Aufrufe gegen die ''pub fn''-Signaturen in ''aurum/std'' gehalten, 0 Abweichungen).
Letzte Aktualisierung: 2026-08-30 — Beispielausgaben gegen ''lyxc 1.1.14A'' nachgezogen: ''Unescape'' löst alle Entities auf, ''Escape'' lässt UTF-8 unangetastet (#1418, #1419) und ''ValidateBalance'' zählt leere Elemente sowie ein ''<'' im Text nicht mehr als offenes Tag.