问题
尽管在我的一些 Clojure 代码中零零星星地包含了一些 JavaScript、XML 和 HTML,但不得不转义引号仍然很麻烦,容易出错。这在脚本和运行 shell 命令时也同样适用,你可能会遇到复杂的转义场景。
解决方案
添加一个字符串字面量,可以适应包含任何类型的字符串,而无需转义。
建议
文本块
某些其他语言提供一种称为文本块的功能,您可以在此处使用三个或更多的引号来编写字符串,其中允许所有字符
(println """
This " is allowed,
and no need to escape it.
"""
文本块通常还带有其他一些功能,第一个和最后一个换行符不属于字符串的一部分。并且源代码中三引号的位置区分引号中行的开始。因此,上述代码打印出
This " is allowed,
and no need to escape it.
而不是
This " is allowed,
and no need to escape it.
虽然文本块在视觉上很整洁,因为它们在源代码中有很好的对齐。但是,它们是空白相关的,而 Clojure 一直是一个空白无关的语言,这意味着空白不重要。我认为最好是保持这种方式。因此,接下来的两个建议。
原始字符串
有时没有“块”功能的文本块被称为原始字符串字面量
(println """This " is allowed,
and no need to escape it.
Also support multi-line, but
not the "block" style of text blocks.""")
因此
(println """
This " is allowed,
and no need to escape it.
"""
打印出
This " is allowed,
and no need to escape it.
不像文本块。
如果您需要三引号,只需把分隔符换成四引号
""""This """ is now allowed as well.""""
原始字符串的问题在于,如果您使用双引号作为您的分隔符
""This is a raw " string!""
但想将单引号放在开头或结尾
"""{{hello}}"""
我想的字符串是:"{{hello}}"
,不是 {{hello}}
,但原始字符串无法区分这两者,因为现在它认为这是三引号分隔符。
一个解决方案是允许仅在开头或结尾使用转义引号
""\"{{hello}}\"""
但不能在中间使用
""\"{{he\llo}}\"""
这是这个字符串:"{{he\llo}}"
所以转义字符 \\
出现在除开头外任何地方,如果后面跟着引号;在结尾处,如果后面跟着引号。
但我仍然觉得这并不理想。规则太多,仍然有需要转义的情况。
未转义的字符串(我最喜欢的)
这里的想法是允许任何字符串作为分隔符。因此,对于我们要嵌套在Clojure代码中的任何可能字符串,我们都可以找到一个不包含它的字符串用作分隔符。
假设添加了读取宏 #text。它期望以下形式是普通字符串,以此告诉它后续读取形式的分隔符。
(println #text "|" |"{{hello}}"|)
会打印
"{{hello}}"
《#text》的第一个参数告诉它以下原始字符串的分隔符应该是哪个。这样,你绝对不需要在原始字符串内使用转义序列。对于任何给定的字符串,你都可以找到一个不包含它的分隔字符串以正确处理。
关于这种方法,我想的一个疯狂的点是,如果你使用一个足够随机的字符串作为分隔符,这可能是一种奇怪的方式来防止注入。
(println #text "xIBgdSl4TCCOIdqdMu9G" xIBgdSl4TCCOIdqdMu9G
Can't nobody guess the delimiter to escape the string context :p
xIBgdSl4TCCOIdqdMu9G)
谢谢