正则表达式在 Tcl 中不匹配带有 [] 和 / 的字符串

Regexp not matching string with [] and / in Tcl

我无法将正则表达式与具有 /[] 模式的引脚名称相匹配。如何在 tcl regexp 中用这个表达式匹配字符串?

问题:

% set inst "channel/rptrw12\[5\]"
channel/rptrw12[5]
% set pin "channel/rptrw12\[5\]/rpinv\[11\]/vcc"
channel/rptrw12[5]/rpinv[11]/vcc
% regexp -nocase "^$inst" $pin
0

通过案例:

% regexp -nocase vcc $pin
1
% set pat "ctrl/crdtfifo"
ctrl/crdtfifo
% set pin2 "ctrl/crdtfifo/iwdatabuf"
ctrl/crdtfifo/iwdatabuf
% regexp -nocase $pat $pin2
1

如果您还记得正则表达式,[] 语法在正则表达式中具有特殊含义。它定义了一个字符组。例如:

[abc]

表示匹配abc.

因此模式:

channel/rptrw12[5]

表示匹配字符串:

channel/rptrw125

如果你想匹配正则表达式中的文字字符 [ 你需要将它转义(与正则表达式中有意义的所有其他字符相同,如 .?( 等)。所以你的模式应该是:

channel/rptrw12\[5\]

但请记住,字符 \[ 在 tcl 字符串中具有特殊含义。所以你的代码必须做:

set inst "channel/rptrw12\\[5\\]"

第一个 \ 转义了 \ 字符,以便 tcl 将单个 \ 插入到字符串中。第三个 \ 转义 [ 字符,这样 tcl 就不会尝试执行名为 5.

的命令或函数

或者你可以使用 {} 而不是 "":

set inst {channel/rptrw12\[5\]}

你的问题是你正在与 RE 引擎元字符作斗争,特别是 […],它定义了一个字符集。如果您想继续使用当前的方法,则需要添加更多反斜杠。

但你不必那样做!

如果你问的是“这个字符串是否存在于那个字符串中?”您也可以考虑使用其中之一:

  1. 使用string first并检查结果(子串所在的位置)是否为负数:

    if {[string first $inst $pin] >= 0} {
        puts "Found it"
    }
    
  2. 使用regexp ***=,意思是“将其余部分解释为文字字符串,没有元字符”:

    if {[regexp ***=$inst $pin]} {
        puts "Found it"
    }
    

如果您只想匹配字符串开头的相等性(您问的是“这个字符串 start 是否与那个字符串相同?”)您可能应该改为其中之一:

  1. 使用string first并检查结果索引是否为零:

    if {[string first $inst $pin] == 0} {
        puts "Found '$inst' at the start of '$pin'"
    }
    
  2. 使用 string equal 和正确的选项(非常类似于 C 中的 strncmp(),如果你知道的话):

    if {[string equal -length [string length $inst] $inst $pin]} {
        puts "'$pin' starts with '$inst'"
    }