2024 Clojure状态调查中分享您的想法!

欢迎!请查看关于页面以了解有关此工作的更多信息。

+8
语法和读取器
编辑

问题

由于不时需要在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)

谢谢

3 个答案

+1
by

在Clojure的生命周期中,人们多次提出了这一请求并被拒绝,我认为这里没有新的论点。

by
嗯,我首先尝试搜索了一下。没有找到任何内容。我受到了即将到来的Java JEPs的启发: https://openjdk.java.net/jeps/355https://openjdk.java.net/jeps/326
by
如果您在Clojure和Clojure-dev谷歌组邮件列表中搜索“原始字符串”,“字符串字面量”,“heredoc”,“多行注释”等,将有很多相关的讨论。

旧版设计页面:https://archive.clojure.org/design-wiki/display/design/Alternate%2Bstring%2Bquote%2Bsyntaxes.html

我认为我应该将“decline”改为“缺乏兴趣”;我认为Rich通常认为这类事情有很多微妙复杂性(尤其是对于工具而言),但收益相对较低。
不同意使用三引号方法的论点是,这已经是合法的Clojure代码。

user=> (println """
这已经是有效的Clojure代码
""")
 
这已经是有效的Clojure代码
 
nil
user=>

(这不代表你想要的意思,但它现在是有效代码,尽管我觉得任何实际的代码都不会这么做)
好吧,我承认我只在谷歌上搜索了,没有特意查看邮件列表 :p。

我没有考虑过文档字符串作为用例,但这也是一个很好的用例。

关于这也可能引入的工具复杂性,这是个很好的观点。解析heredoc或类似的内容可能会更困难。

如果你看看Ruby、Perl和Python,你会发现似乎没有人能够就正确的做法达成一致,而这三种语言最终都支持了多种方式。

说到工具的不值得付出努力。实际上,工具也可以解决这个问题。不是为了文档字符串用例,而是针对我的代码片段用例。我知道在IntelliJ中有一个模式,它会为你打开另一个缓冲区,让你自由输入,并自动将你输入的字符串进行Java转义。也许我也会为Emacs做类似的事情。
@sean 你的看法很敏锐。无论是什么解决方案,我都会倾向于采用读者标记。所以是 #s """ """ 或者类似的形式。这将解决这个问题的。
仅作记录,Java 15 也引入了这个功能(我知道这是一个仅编译器功能,因此 Clojure 实现与此无关),但也许解决方案空间增长了一点点。

仅作记录,"原始字符串",即不需要过多引用的字符串,结合读取宏,可以实现许多令人惊叹的功能,这些功能目前足够让人烦恼,以至于没有人去用它。
+1

从现状的积极方面来看,-- 把 XML 和 HTML 当作文本处理长期以来让非 Clojure 专业的程序员陷入了糟糕的麻烦,包括不规则的输出、注入、拙劣的转换,以及代码的正确性很难评估!

Clojure 获得一些关于其健壮性的好声誉,得益于建立在数据(而不是字符串)基础上的约定。“Hiccup”和“clojure.xml”约定在 HTML 和 XML 证明非常有效,并且(在我未量化的经验中)在运行时非常便宜,这证明了避免在代码中嵌入大块数据的优点。如果你 确实 有大块数据可以开始,你可以尽快使用 Enlive 等工具解析它们,并将处理完成后作为数据结构。

当然,JavaScript 可能过于宽泛。最好是直接从资源中获取它?如果你在 ClojureScript 中编码,你可以使用一个宏在编译时从与 cljs 文件相同的类路径中获取资源。

总的来说,我认为 Clojure 聪明(我们也很幸运)不使用嵌入和调整代码中的 HTML 和 XML 文字的功能。一开始可能看起来像是一个缺失的功能,但它的缺失对 Clojure 代码的可靠性是一个福祉。

非常好的观点。至于 HTML 和 XML,我也同意。我的动力来自于做服务器端渲染,并在我的 Hiccup 中嵌入一些 JavaScript。

我确实在想 CLJS 是否可以这样嵌入使用,但我认为不能。尽管如此,如果它可以,那将会非常棒。
+1

嗨,

我还想支持向Clojure添加此功能。我认为,对像样式化组件https://styled-components.npmjs.net.cn/这样的功能的支持是一个很好的用例。

const Button = styled.a`
  /* This renders the buttons above... Edit me! */
  display: inline-block;
  border-radius: 3px;
  padding: 0.5rem 0;
  margin: 0.5rem 1rem;
  width: 11rem;
  background: transparent;
  color: white;
  border: 2px solid white;

  /* The GitHub button is a primary button
   * edit this to target it specifically! */
  ${props => props.primary && css`
    background: white;
    color: palevioletred;
  `}
`

上面代码的主要优势在于大部分内容都是纯CSS - 不需要转换到Clojure。

在Clojure中添加原始字符串/区块文本有问题吗?是的。
让我们就此问题展开讨论,看看我们能走多远。

有没有一种方法可以像现在Java JEPs的开发方式一样,以类似的方式在Clojure中实验其功能 - 具有预览版本以供发现和改进,直到最终确定并添加到核心?https://openjdk.java.net/jeps/326

我对Clojure相当陌生,我对这个语言及其历史和传统不太熟悉。我并不喜欢挑战传统,因为世界在变化。曾经使我们的做事方式合理的理由,现在可能不再成立。

Clojure没有类似Java JEPs的过程。如果Rich Hickey对功能不感兴趣,那么他不会将其作为Clojure官方版本的一部分进行整合。

世界上任何人都可以为Clojure源代码创建自己的本地修改,并使用它,如果他们愿意的话。我听说有一些组织运行自己的Clojure打补丁版本用于自己的用途。

为您自己的Clojure副本添加此类功能将非常简单。但这并不能帮助在分布式Clojure程序中使用此功能,因为使用官方Clojure版本的人将无法编译和运行使用新功能的源代码。
我希望能有Clojure中的文本块。
我使用的场景是嵌入其他编程语言,例如Python。

“文本块”是实现这一功能的需求之一,否则如果仅关注引号问题,那会过于繁琐。
...