我的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 :)作为输出。如何解决此问题。
谢谢,
库马尔
答案 0 :(得分:1)
尝试使用
regexp {number n1.*?(numbers .*)\n} $test x y
(请注意,我与test
匹配。无需替换换行符。)
与您的模式有两点不同。
您的模式告诉regexp
匹配从第一次出现number n1
到最后出现的numbers
,并且确实如此。这是因为它们之间的.*
匹配是 greedy ,即它匹配尽可能多的字符,这意味着它超过了第一个numbers
。
使比赛变得非贪婪意味着该模式将从第一次出现number n1
到下一次numbers
匹配,这就是您想要的。
在numbers
之后,还有另一个.*
匹配,这有点麻烦。如果它是贪婪的,那么它将匹配变量内容结尾的所有内容。如果它不贪婪,它就不会匹配任何字符,因为匹配零长度字符串会满足匹配。另一个问题是Tcl RE引擎并不真正允许从非贪婪模式切换回来。
您可以通过强制模式匹配您想要.*
匹配的文本之前的一个字符来解决此问题,从而使零长度匹配无效。匹配换行符(\n
)或空格(\s
)字符应该有效。 (这当然意味着必须是每个数据字段后的换行符/其他空格字符:如果数字字段是变量中该字段无法找到的最后一个字符范围。)
答案 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缓存效率降低。)