【问题标题】:Tcl regsub used with subst produces unexpected resultTcl regsub 与 subst 一起使用会产生意外的结果
【发布时间】:2017-05-17 21:36:46
【问题描述】:

编辑: 对于给定的 str 参数,我试图用“xor_in[0]”替换“xor_in0”,用“xor_in[1]”替换“xor_in1”。这里“xor_in0”、“xor_in1”是传入的参数,我将其表示为“key”,而“xor_in[0]”、“xor_in[1]”是存储在数组中的值参数。注意这里的重点是将 "str" 中的每个 "key" 替换为 "value" 。这是我的测试代码:

set str "(xor_in0^xor_in1)"
set str1 "xor_in0^xor_in1" # another input
set key "xor_in0"
set value "xor_in\[0\]"
set newstr ""
set nonalpha  "\[^0-9a-zA-Z\]"
regsub -all [subst {^\[(*\]($key)($nonalpha+)}] $str [subst -nobackslashes {$value\2}] newstr
puts $newstr

但不知何故,它不起作用...我也尝试删除 [subst ...],但它仍然无法匹配任何内容。这在某种程度上违背了我对正则表达式的了解。请帮忙。

【问题讨论】:

  • 首先要检查:输入 regsub 的字符串是否符合您的实际期望?
  • 你的意思是 $str 还是 [subst ...]? $str 是正确的。但是 [subst ...] 会让事情变得复杂,我怀疑会有一些问题。但我不知道如何调试它。我需要 subst 来评估传递给函数的参数。
  • 我认为问题在于 [subst] 和 {} 一起使用。如果我不使用 {},而是使用“”,它会起作用:regsub -all "[subst $key]" $str [subst {$value}] newstr。但这不是我想要的……我需要匹配“^”符号和()来保留剩余的……

标签: regex tcl


【解决方案1】:

对我来说,一切似乎都过于复杂了。

让我们看看您实际要执行的regsub。轻松做到这一点有一个技巧。如果你的命令是:

regsub -all [subst {^\[(*\]($key)($nonalpha+)}] $str [subst -nobackslashes {$value\2}] newstr

然后我们可以打印出它将尝试做什么:

puts [list regsub -all [subst {^\[(*\]($key)($nonalpha+)}] $str [subst -nobackslashes {$value\2}] newstr]

这表明你真的这样做了:

regsub -all {^[(*](xor_in0)([^0-9a-zA-z]+)} (xor_in0^xor_in1) {xor_in[0]\2} newstr

其中看起来有点奇怪的部分是 RE 末尾的 ([^0-9a-zA-z]+)。这是合法,但很奇怪,因为我们可以用\W 写一些不同的东西来匹配非alpha:

regsub -all {^[(*](xor_in0)(\W+)} $str {xor_in[0]\2} newstr

这似乎奏效了。那么错误可能是什么? nonalpha 的定义,因为您使用的是 "\[^0-9a-zA-z\]" 而不是 "\[^0-9a-zA-Z\]" 是的,文字 ^ 位于从 A 到 @ 的 ASCII(和 Unicode)范围内987654333@…


OTOH,我实际上希望真正像这样进行转换:

set newstr [regsub -all {(\y[a-zA-Z]+_in)(\d+)} $str {\1[\2]}]

您不习惯的只有\y(字边界约束)和\d(匹配任何数字)。或者,对于简单的转换(将文字子字符串的所有实例映射到另一个文字子字符串):

set newstr [string map [list $key $value] $str]

【讨论】:

  • 谢谢。 A-z 是一个错字:) 你的第一个答案给了我一个很好的概括。最后一个真的很酷。我不是 Tcl 程序员,但它改变了我对正则表达式使用的看法。
  • 再想一想,最后一个似乎不太合适。我无法将“xor_in12”更改为“xor_in[1]2”。相反,它应该是“xor_in[12]”。这就是我猜使用正则表达式的原因。我会看看第一个答案是否更好。
  • 您的第一个答案也不起作用。如果您直接使用“xor_in0”字符串,它可能会起作用。但是这里的问题是由使用“key”参数并在 {} 块内进行评估引起的。所以直接字符串的解决方案将无济于事。为了更好地理解,我稍微更新了评论。
【解决方案2】:

实际上我的问题的真正问题是 A-z 错字:)

【讨论】:

    【解决方案3】:

    简单通常更好:

    regsub -all {\d+} $s {[&]} s
    

    照顾您的示例。

    【讨论】:

    • 感谢您的帮助。这太简单了 :) 传入的键、值和要替换的字符串可能不包含 \d,尽管这是正常情况。但原始语法将涵盖其中的大部分,如果不是全部的话。
    猜你喜欢
    • 2012-03-30
    • 2017-11-14
    • 1970-01-01
    • 1970-01-01
    • 2015-03-08
    • 1970-01-01
    • 2021-03-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多