Scala 字符串插值器不支持转义双引号
文章目录
【注意】最后更新于 March 19, 2021,文中内容可能已过时,请谨慎使用。
用 \" 在字符串中插入双引号时,出现语法错误:; expected but string constant found。
| |
tl;dr
这不是 bug 而是 feature !(至少是明确 won’t fix 的 bug)
冷知识
- 形如
"..."的字符串字面量(加上转义字符)可以表示所有的字符串 - 形如
"""..."""的字符串不能表示""" - 使用插值器之后,形如
s"..."的字符串和形如s"""..."""的字符串都无法表示所有的字符串
正确的插入方式:
| |
以上2个表达式的值均为 color="#0000ff" 。
当然,还可以用 + 运算符拼接多个字符串(如 "color=\"" + color + "\"" ),这种解决方案不在本文的讨论范围内。
引号导致的其它问题
下面看一个来自 GitHub issue 的例子。
| |
通过上面的若干用例,我们可以得出结论:
- 在不用插值器的时候,
\"可以正常被转换为双引号。 - 使用了
s插值器之后,再使用\",编译器就会报错。 - 单引号
\'可以在插值器中使用。 - 在使用
"""声明的字符串中,可以直接使用",\"会被识别为2个字符。
RTFM
在 SIP-11 中, id"string content" 这样的字符串被称为 processed string (准确地说, string content 可以是 standard - " 类型,也可以是 multi-line - """ 类型)。
按照上面手册中的定义,编译器在遇到
| |
时,会将其替换为
| |
SIP-11 中提到:
Inside a processed literal none of the usual escape characters are interpreted (except for unicode escapes) no matter whether the string literal is normal (enclosed in single quotes) or multi-line (enclosed in triple quotes). Instead, there is are two new forms of dollar sign escape. The most general form encloses an expression in
${and}, i.e.${expr}.
大意是说, processed literal 中除 unicode 转义字符外,其余所有的转义字符都不会被替换。另外,这里的 ${ 和 } 可以视为新的转义字符。
SIP-11 在 Standard String Interpolation 一节还提到,字符串插值器 s 返回的字符串为
| |
此处的 esc(str) 代表将字符串 str 中的转义字符替换为对应的符号。
所以,如果 esc 在这里把 \" 替换为 " 的话,替换后的代码中可能出现语法错误,比如
| |
在手册的定义中, StringContext 接受的字符串不含转义字符,插值器需要自己进行转义字符替换的工作。这样定义的好处是,可以实现一个这样的正则表达式插值器:它不识别转义字符,从而书写正则表达式时不必考虑诸如 ' 需要写为 \' 的问题。同时,标准的插值器 s 和 f 等可以正常处理转义字符。
参考资料
- SIP 11
- scala/bug 仓库里的 issue#6476
- Scala Doc on STRING INTERPOLATION
- Google Groups 里的会话 round up the usual escape characters
- Stack Overflow 上的提问 How to insert double quotes into String with interpolation in scala
