std.html
HTML’s escapes of text: escape writes the five characters that
would be read as markup, &, <, >, ' and ", as references,
and unescape reads every reference back, as Go’s html package
does (EscapeString, UnescapeString): the numeric ones, é
and é, and the named ones, all of HTML5’s. Import it by a
name, import std.html as HTML.
import std.html as HTML
-- | a paragraph of the text, whatever is in it-- | >>> paragraph "1 < 2 & \"so\""-- | "<p>1 < 2 & "so"</p>"paragraph : String -> Stringparagraph text = "<p>" ^ HTML.escape text ^ "</p>"escape
escape : String -> StringThe text with &, <, >, ' and " written as &,
<, >, ' and " (as Go’s html.EscapeString
writes them), the rest as it is: in an element’s content or a
quoted attribute’s value, it is read as the text it is.
>>> escape "<a href=\"x\">Tom & Jerry's</a>""<a href="x">Tom & Jerry's</a>">>> List.map escape ["", "plain \u{e9}", "&&", "&"]["", "plain \u{e9}", "&&", "&amp;"]unescape
unescape : String -> StringThe text with each character reference read, as Go’s
html.UnescapeString reads them. &# and decimal digits, or &#x
(or &#X) and hex digits, a ; after them or not, is the code point
they are: one from 0x80 to 0x9F Windows-1252’s character there, as
browsers read it (– is –), and 0, a surrogate or one past
U+10FFFF U+FFFD. &, a name — letters and digits, their case
told apart — and ; is what HTML5 names so. Where there is no
such name, or no ;, the longest of the legacy names that may end
without one (amp, lt, copy, eacute, …) that the name starts
with is read, the rest left after it, as browsers read ©2024.
Any other & — no digits, no name, a name none is — is left as it
is written.
>>> unescape "<p>Tom & Jerry's "café"</p>""<p>Tom & Jerry's \"caf\u{e9}\"</p>">>> List.map unescape ["é", "é", "é", "éx", "😀", "😀"]["\u{e9}", "\u{e9}", "\u{e9}", "\u{e9}x", "\u{1F600}", "\u{1F600}"](Windows-1252’s, and what is no character)
>>> List.map unescape ["–", "€", "", "�", "�", "�", "�"]["\u{2013}", "\u{20AC}", "\u{81}", "\u{FFFD}", "\u{FFFD}", "\u{FFFD}", "\u{FFFD}"](rare names, a name of two code points, one of a character that is a name’s syntax)
>>> List.map unescape ["⋣", "fj", "≫⃒", "\"
", "  "]["\u{22E3}", "fj", "\u{226B}\u{20D2}", "\\\"\n", "\u{205F}\u{200A}"](legacy names without their ;, and the longest of them first)
>>> List.map unescape ["©2024", "&", "<x", "¬it;", "¬", "∉", "¾x", "&&"]["\u{a9}2024", "&", "<x", "\u{ac}it;", "\u{ac}", "\u{2209}", "\u{be}x", "&&"](left as they are written: no name, no digits, a name none is, a
name not legacy without its ;, a name in the wrong case)
>>> List.map unescape ["&", "& ", "&;", "&#", "&#;", "&#x;", "&#xg;", "&nosuch;", "&hellip", "&Amp;", "a&b", "&<"]["&", "& ", "&;", "&#", "&#;", "&#x;", "&#xg;", "&nosuch;", "&hellip", "&Amp;", "a&b", "&<"]