【问题标题】:General string quoting for TCLTCL 的通用字符串引用
【发布时间】:2011-03-14 17:29:24
【问题描述】:

我正在编写一个实用程序(恰好在 python 中),它以 TCL 脚本的形式生成输出。给定python中的一些任意字符串变量(不是unicode),我想生成一个像

这样的TCL行
set s something

... 这会将 TCL 变量 's' 设置为该确切的字符串,而不管其中有什么奇怪的字符。没有变得太奇怪,我不想让输出比需要的更混乱。我相信一个体面的方法是

  1. 如果字符串不为空并且只包含字母数字,以及一些像.-_(但绝对不是$"{}\)这样的字符,那么它可以按原样使用;

  2. 如果它只包含可打印的字符并且没​​有双引号或花括号(并且不以反斜杠结尾),那么只需在其周围加上 {}

  3. 否则,在使用 \ 转义为 " { } } \ $ [ ] 和 @9999 - 打印字符。

问题:这是需要在双引号内转义的完整字符集吗?我在文档中找不到这个。我错过了什么吗(例如,我几乎错过了 (2) 的字符串不能以 \ 结尾)。

我知道{} 可以引用许多其他字符串,但似乎很难轻松识别它们。此外,如果您不介意 TCL 输出中确实存在非打印字符(特别是换行符),那么 (2) 看起来也可以。

【问题讨论】:

  • 对于非打印字符,\nnn 是什么意思?
  • @GaryWilloughby 反斜杠后跟三个八进制数字是可用于非打印字符的转义。我知道 unicode 有转义; unicode 超出了我的问题范围,但很高兴看到一些答案涵盖了它。

标签: tcl quoting


【解决方案1】:

你真的只需要两条规则,

  • 转义花括号
  • 将输出括在花括号中

您无需担心换行符、不可打印字符等。它们在文字字符串中有效,并且 TCL 具有出色的 Unicode 支持。

set s { 
this is
a 
long 
string. I have $10 [10,000 cents] only curly braces \{ need \} to be escaped.
\t is not  a real tab, but '    ' is. "quoting somthing" :
{matchin` curly braces are okay, list = string in tcl}
}

编辑 根据您的评论,您可以执行以下操作:

  • 转义[]{}$
  • 将整个输出包装在set s [subst { $output } ]

Tcl 的美妙之处在于它具有非常简单的语法。除上述3个字符外,没有其他字符需要转义。

编辑 2 最后一次尝试。

如果你传递subst一些选项,你只需要转义\{}

set s [subst -nocommands -novariables { $output } ]

但是,您需要想出一个正则表达式来将不可打印的字符转换为其转义代码。

祝你好运!

【讨论】:

  • 但我发现这一点:转义卷曲会阻止在找到匹配的端卷曲时考虑它们,但不会删除反斜杠(因为它们用于双引号)即结果仍然会有我添加到原始卷曲的反斜杠。
  • OK... 我没有想过使用 TCL 命令来完成这项工作。但看起来我除了 [] {} $ 之外还需要转义反斜杠 - 所以它与双引号情况几乎相同(但不需要转义“。)转义不可打印的字符是我想要的即使没有必要也要做。
  • 转义花括号似乎不起作用,因为它只会在实际字符串中产生\}
  • 另外,“Tcl 的美妙之处在于它有一个非常简单的语法”似乎与您为解决这个问题而进行的三个尝试相冲突!
【解决方案2】:

一旦你在一个双引号字符串中,Tcl 的元字符就很少了,所有的元字符都可以通过在它们前面加一个反斜杠来引用。您必须引用的字符是 \ 本身、$[,但也引用 ]{} 被认为是一种很好的做法,以便脚本本身是可嵌入的。 (Tcl 自己的list 命令可以做到这一点,只是它实际上并不包含双引号,因此它也处理反斜杠,并且它还会尝试在“好”字符串上使用其他技术。有一个算法可以做到这一点,但我建议不要为代码中的复杂性而烦恼;简单的通用规则对于正确编码要好得多。)

第二步是将数据放入Tcl。如果你正在生成一个文件,你最好的选择是将它写成 UTF-8 并使用-encoding 选项到 tclsh/wish 或 source 命令来明确说明编码是什么。 (如果您在同一进程中,请将 UTF-8 数据写入字符串并对其进行评估。作业完成。)该选项(在 Tcl 8.5 中引入)专门用于处理此类问题:

source -encoding "utf-8" theScriptYouWrote.tcl

如果这不可能,您将不得不退回到添加额外的引用。最好的办法是假设您只有可用的 ASCII 支持(一个很好的最低公分母)并引用其他所有内容作为第一段中描述的引用的单独步骤。引用,将每个 Unicode 字符从 U+00080 转换为 \uXXXX 形式的转义序列,其中 XXXX 正好是四个十六进制数字[1],另外两个是文字字符。不要使用\xXX 表单,因为它有一些“令人惊讶的”错误功能(唉)。


[1] Tcl 中有一个关于处理基本多语言窗格之外的字符的开放错误,部分\u 表单无法处理应付。幸运的是,非 BMP 字符在实践中仍然相当少见。

【讨论】:

    【解决方案3】:

    要做到这一点,您还应该指定 Python 字符串所在的编码,通常是 sys.getdefaultencoding()。否则,在将其转换为 Tcl 时,您可能会出现乱码。

    如果您的字符串中有二进制数据并且想要 Tcl 二进制字符串作为结果,这将始终有效:

    data = "".join("\\u00%02x" % ord(c) for c in mystring)
    tcltxt = "set x %s" % data
    

    虽然看起来像一个十六进制转储,但是,它是一个十六进制转储...

    如果您使用任何特殊编码,如 UTF-8,您可以通过使用编码 convertfrom/convertto 和适当的 Python 习语来增强这一点。

    data = "".join("\\u00%02x" % ord(c) for c in myutf8string)
    tcltext = "set x [encoding convertfrom utf-8 %s]" % data
    

    您当然可以稍微改进一下,避免所有非特殊字符的 \u 编码,但无论如何以上都是安全的。

    【讨论】:

      【解决方案4】:

      据我所知,必须:

      1. 用双引号将字符串括起来""
      2. 反斜杠转义以下字符:[$"\

      其他答案在各个方面都是错误的:

      • 确实需要逃脱"
      • 不需要在双引号字符串中转义]{}
      • 您不能使用{this style of string},因为无法在其中放置不平衡的大括号。 { \} } 不起作用,因为它在字符串中保留了反斜杠。

      规范对此非常不清楚,甚至在某些地方是错误的(例如,它说\n 将被{curley bracket strings} 中的换行符替换,但实际上并没有发生。所以我主要从实验中发现了这一点在 repl.it 上。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-30
        • 2011-08-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多