问题
曾不得不在一些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)
谢谢