获取最后一次出现的包含子字符串的行

Fetch a last occurrence of row containing a substring

我有一个字符串 a

set $a "I have a blah blah
xyz who r u
I have a car
xyz j r u"

I have a blah blah 
xyz who r u   // Line 2 which contains substring xyz
I have a car
xyz j r u     //Line 4 which contains substring xyz

我在用新行拆分字符串变量 $a 后对变量 a 使用 foreach 循环。

set substring "xyz"
set b [split $a '\n']
foreach eachLine $b {
            if{[string first $substring $eachLine] != -1} {
                puts "$eachLine"   
            }
}

我希望输出为:

xyz j r u  //Line 4 which contains substring xyz

目前,这将同时打印第 2 行和第 4 行。

在上面的代码中,我试图获取出现子字符串“xyz”的最后一行。 能否请您提出解决此问题的任何好方法。

您可以将 $eachLine 存储在一个变量中,然后仅在循环结束后打印它。

set lastSeen ""
foreach eachLine $b {
    if {[string first $substring $eachLine] != -1} {
        set lastSeen $eachLine
    }
}
puts $lastSeen

您可以颠倒列表并打印第一次看到它的时间:

foreach line [lreverse $b] {
    if {[string first $substring $line] != -1} {
        puts $line
        break   
    }
}

搜索列表的内置方法是 lsearch 命令。您可以使用 lindex 命令仅提取最后一次出现:

puts [lindex [lsearch -all -inline -regexp $b (?q)$substring] end]

这使用了 -regexp 选项,因此搜索模式不是固定的(即:它可能出现在列表元素中的任何位置)。然后 (?q) 嵌入选项禁止将 $substring 中的任何字符解释为正则表达式语法,从而导致对存储在 $substring.

中的文字文本进行搜索

从末尾向前遍历行列表,并在第一个匹配处停止:

set i [expr {[llength $b] - 1}]

while {$i >= 0} {
  set eachLine [lindex $b $i]
  if {[string first $substring $eachLine] != -1} {
    puts "$eachLine"
    break;
  }
  incr i -1
}

这样您就不会加倍列表 (lreverse) 或处理整个列表 (lsearch),只检索一个匹配项(如果有的话)。