Tcl

时间:2016-05-17 19:36:05

标签: regex tcl

我有somefile.txt,包含如下行:

{ abc1 } 1
{ cde1 } 101
{ fgh1 } 1
{ ijk1 } 2 

它是一个巨大的文件,我想只找到第1行和第3行并计算它们。

我已尝试使用{\s\}\s1\n}的regexp和lsearch(将其转换为列表),但它不起作用。我该怎么做......?

我也尝试了{\s\}\s1},但它打印了所有4行。

3 个答案:

答案 0 :(得分:0)

您似乎需要捕获第一行和第三行末尾的数字。

以下是实现这一目标的方法:

set s {{ abc1 } 1
{ cde1 } 101
{ fgh1 } 1
{ ijk1 } 2}
set re {^{[^{}]*}\s*(\d+)\s+{[^{}]*}\s*\d+\s+{[^{}]*}\s*(\d+)}
regexp $re $s m g1 g2
set res [expr $g1 + $g2]
puts $res

请参阅IDEONE demo

模式匹配:

  • ^ - 字符串的开头
  • {[^{}]*} - 一个{...} - 类似字符串,里面没有大括号
  • \s* - 0+ whitespaces
  • (\d+) - 第1组(g1)捕获1+位数
  • \s+ - 1+个空格(如果之前和之后不能有尾随/前导空格,则可以用[\r\n]+替换)
  • {[^{}]*}\s*\d+\s+{[^{}]*}\s*(\d+) - 见上文,只有(\d+)会创建第二个变量g2

请参阅regex demo

答案 1 :(得分:0)

如果您不使用正则表达式,这样的问题会更容易解决。

package require fileutil

::fileutil::foreachLine line somefile.txt {
    if {[lindex $line end] == 1} {
        puts $line
    }
}

此解决方案查看文件中的每一行,并检查最后一项是否等于1.如果是,则打印该行。

你也可以统计他们/总结他们:

set count 0
set sum 0
::fileutil::foreachLine line somefile.txt {
    if {[lindex $line end] == 1} {
        puts $line
        incr count
        incr sum [lindex $line end] ;# yeah, I know, always 1
    }
}
puts "Number of lines: $count"
puts "Sum of items: $sum"

如果您的Tcl安装中没有fileutil,并且您无法或者不想安装它,您可以使用较低级别的核心等效项:

set f [open somefile.txt]
while {[gets $f line] >= 0} {
    if {[lindex $line end] == 1} {
        puts $line
    }
}
close $f

如果你绝对必须使用正则表达式,在这种情况下你可以这样做:

::fileutil::foreachLine line somefile.txt {
    if {[regexp {\m1$} $line]} {
        puts $line
    }
}

这个正则表达式找到单词中以数字1结尾的行(即它前面没有数字或单词字符)。

文档:closefileutil包,getsiflindexopenpackage,{{ 3}},putsSyntax of Tcl regular expressionsregexp

答案 2 :(得分:0)

解决方案1:如果您不想使用regexp,并且您的输入行具有与{string} number相同的格式

set fd [open "somefile.txt" r]
while {[gets $fd line] >= 0} {
    if {[lindex $line 1] == 1} {
        puts [lindex $line 1] ;# Prints only 1
        puts $line            ;# Prints Whole Line which has 1 at end
    }
}

解决方案2 :如果您要使用regexp,请转到group-capturing (.*)

set fd [open "somefile.txt" r]
while {[gets $fd line] >= 0} {
    if {[regexp "\{.*\} (.*)" $line match match1]} {
        if {$match1 == 1} {
            puts $line
        }
    }
}

解决方案3:基于regexp上的@Peter建议

set fd [open "somefile.txt" r]
while {[gets $fd line] >= 0} {
    if {[regexp {\d+$} $line match]} {
        if {$match == 1} {
            puts $match ;# Prints only 1
            puts $line  ;# Prints whole line which has 1 at end 
        }
    }
}