It seems to me, though, that escaping is just something that's going to be tricky everywhere, and a decent first line solution, wherever you are, is to have a really rare set of characters represent your begin/end string marks. In Python, """text""", Postgres has $$text$$, non-ASCII characters in other formats. XML and sexps are both susceptible to that issue-- both of their escapes are, themselves, escapable. To either one, if you have a subregion that's likely to be unintentionally escaped, then you create a boundary where you either explicitly escape every one, or you refuse to acknowledge previously accepted delimiters. As an example, lisps have (quote term) rather than 'term when you're writing macros and concerned with macro-expansion.
To your regex point, there are lisps that definitely did awful deeds with that, particularly emacs lisp, but the more recent ones have solutions just like other modern programming languages and markups do.
To me the unending escape just kind of seems like a universal bug. While lisp is just as susceptible, lisps have perfectly reasonable ways of treating these problems-- separate, make distinct, and as last resort, escape.
A few things usually going on with S-expression representation of XML or HTML encoding in a Lisp:
1. It uses some of the native basic types of Lisp -- the list, the symbol, and the string.
2. The HTML element values that you type in your source and that are displayed to you are generally in the same syntax, since that's how Lisps tend to work with the basic types. (For contrast, you don't type your HTML like `<html><body><p>Hi</p></body></html>` in your source, and then see it in the debugger like `HtmlElement#abcd1234("html", {HtmlElement#c948f447("body", {HtmlElement#e7e7e7e7("p", {HtmlCdata#c8c8c8c8c8("Hi")})})})`.
3. The S-expression printed representation you see in your source can be less verbose than HTML or XML, such as by not needing HTML element end tags. Though you will have to put your HTML CDATA text as quoted string literals.
4. A Lisp person's typical code indenting (supported by the editor), tends to expose the tree/forest structure of HTML conveniently:
(html (head (title "My Page"))
(body (p "First paragraph.")
(blockquote "Don't quote me on that.")
(div (p "Another paragraph.")
(p "Yet another paragraph."))
(p "Hey, it's a paragraph.")))
Note that I probably wouldn't type a huge book this way. I might instead use Markdown or a DSL or alternate reader, such as Scribble or its at-reader, mainly to get TeX-like paragraphs: https://docs.racket-lang.org/scribble/ https://docs.racket-lang.org/scribble/reader-internals.htmlTag inference/omission in SGML (and by extension HTML when seen as an application of SGML) is way more powerful. A minimal, valid HTML document is this:
<title>Whatever title</title>
<p>Text goes here
SGML's tag inference, when coupled with a DTD for HTML5 such as mine [1], will treat that as equivalent to this: <html>
<head>
<title>Whatever title</title>
</head>
<body>
<p>Text goes here</p>
</body>
</html>
See details in slides or paper linked from [2].