TCL_REGEXP ::如何从TCL中看起来类似的变量grep一行

时间:2014-09-14 16:30:19

标签: regex tcl

我的TCL脚本:

set test {
a for apple
b for ball
c for cat
number n1
numbers 2,3,4,5,6
d for doctor
e for egg
number n2
numbers 56,4,5,5
}

set lines [split $test \n] 
set data [join $lines :]
if { [regexp {number n1.*(numbers .*)} $data x y]} {
    puts "numbers are : $y"
}

如果我运行上述脚本,则输出当前输出:

C:\Documents and Settings\Owner\Desktop>tclsh stack.tcl
numbers are : numbers 56,4,5,5:

C:\Documents and Settings\Owner\Desktop>

预期产出:

在脚本regexp中,如果我指定“数字n1”......它应该打印“数字是:数字2,3,4,5,6”     如果我指定“数字n2”......它应该打印“数字是:数字为53,5,5,5:”

现在它总是打印最后一行(最后一行 - 数字为53,5,5,5 :)作为输出。如何解决此问题。

谢谢,

库马尔

2 个答案:

答案 0 :(得分:1)

尝试使用

regexp {number n1.*?(numbers .*)\n} $test x y

(请注意,我与test匹配。无需替换换行符。)

与您的模式有两点不同。

  1. 第一颗星背后的问号使得匹配非贪婪
  2. 捕获括号后面有一个换行符。
  3. 您的模式告诉regexp匹配从第一次出现number n1到最后出现的numbers,并且确实如此。这是因为它们之间的.*匹配是 greedy ,即它匹配尽可能多的字符,这意味着它超过了第一个numbers

    使比赛变得非贪婪意味着该模式将从第一次出现number n1到下一次numbers匹配,这就是您想要的。

    numbers之后,还有另一个.*匹配,这有点麻烦。如果它是贪婪的,那么它将匹配变量内容结尾的所有内容。如果它不贪婪,它就不会匹配任何字符,因为匹配零长度字符串会满足匹配。另一个问题是Tcl RE引擎并不真正允许从非贪婪模式切换回来。

    您可以通过强制模式匹配您想要.*匹配的文本之前的一个字符来解决此问题,从而使零长度匹配无效。匹配换行符(\n)或空格(\s)字符应该有效。 (这当然意味着必须是每个数据字段后的换行符/其他空格字符:如果数字字段是变量中该字段无法找到的最后一个字符范围。)

    文档:regular expression syntaxregexp

答案 1 :(得分:0)

在正则表达式中使用Tcl变量很容易。无论如何,在一个级别上:你将正则表达式放在双引号中,这样你就可以在之前中将标准的Tcl变量替换为传递给RE引擎:

# ...
set target "n1"
if { [regexp "number $target.*(numbers .*)" $data x y]} {
    # ...

困难的是,您必须记住,从" ... "切换到{ ... }会影响整体< / em>该单词,并且该替换是正则表达式片段。我们通常建议您使用{ ... },因为在大多数情况下,这样做更容易获得一致和不正确。

让我们来说明这会如何变得烦人。在您的具体情况下,可能想要实际使用它:

if { [regexp "number $target\[^:\]*:(numbers \[^:\]*)" $data x y]} {

此处的字符集排除了:(您已经 - 不必要地 - 用作换行符),但因为[ ... ] 也是标准Tcl metasyntax,你必须反斜杠 - 引用它。 (当你想要总是将变量的内容用作文字时,即使它们可能包含RE metasyntax字符,事情也会变得非常烦人;你需要regsub调用来整理一些东西。并且你开始可能使Tcl的RE缓存效率降低。)