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: <a href="x">Tom & Jerry's</a>
Entities: & < > " ' ' A &unknown;
UTF-8: CafM-C Grand-MM-CM-(re
Die letzte Zeile ist durch ''cat -v'' sichtbar gemacht: ''M-C'' steht für das Byte 0xC3. Aus ''à'' (C3 A0) wurde ''C3'' + '' '' — ein halbes UTF-8-Zeichen gefolgt von einer Entity. ''è'' (C3 A8) blieb dagegen unversehrt, weil nur 0xA0 geprüft wird.
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
'): 1
Balance('
'): 1
Balance('5 < 7 und 9 > 2'): 1
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'' rechnet naiv.** Jedes ''<'' zählt als geöffnet, jedes ''</'' als geschlossen — unabhängig davon, ob überhaupt ein Tag vorliegt:
>
> * **Void-Elemente** (''<br>'', ''<img>'', ''<meta>'', ''<input>'', ''<hr>'') gelten als offen; gültiges HTML bekommt eine Bilanz ungleich null.
> * **Selbstschließende Tags** (''<img/>'') ebenfalls, obwohl ''IsSelfClosing'' sie erkennen könnte.
> * Ein ''<'' im **Fließtext** (''5 < 7'') zählt mit.
>
> Brauchbar ist die Funktion damit nur für streng gepaartes, XML-artiges Markup ohne Void-Elemente ([[https://github.com/SEOLizer/LyX-Compiler/issues/1420|#1420]]).
----
===== 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-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''.