regexp循环查找每个查询TCL的第一个实例

时间:2016-05-31 02:23:52

标签: regex tcl

我有一个包含一些值的列表变量:

lappend list {query1}
             {query2}
             {query3}

file1中的一些数据,其中部分数据与上面的值匹配

query1 first data 
query1 different data
query1 different data
query2 another data  
query2 random data 
query3 data something 
query3 last data 

如何创建一个正则表达式循环,仅捕获每个查询的第一个实例并将其打印出来?在这种情况下,输出将是:

query1 first data
query2 another data 
query3 data something

尝试生成输出的代码

set readFile1 [open file1.txt r]
while { [gets $readFile1 data] > -1 } {
for { set n 0 } { $n < [llength $list] } { incr n } {
if { [regexp "[lindex $list $n]" $data] } {
puts $data
}
}
}
close $readFile1

我尝试在从文件中读取数据时使用for循环,但即使未使用-all选项,它似乎也会捕获所有值。

4 个答案:

答案 0 :(得分:2)

如果文本文件较小,您可以使用read命令将文件整体读入变量。对内容应用regexp,我们可以提取所需的数据。

set list {query1 query2 query3}
set fp [open file1.txt r]
set data [read $fp]
close $fp
foreach elem $list {
    # '-line' flag will enable the line sensitive matching
    if {[regexp -line "$elem.+" $data line]} {
        puts $line
    }
}  

如果假设文件太大而无法容纳或者考虑运行时内存使用情况,那么请继续逐行读取内容。在那里,我们需要控制已经匹配的内容,您可以保留数组以维护是否匹配任何查询的第一次出现。

set list {query1 query2 query3}
set fp [open file1.txt r]
array set first_occurence {}
while {[gets $fp line]!=-1} {
    foreach elem $list {
        if {[info exists first_occurence($elem)]} {
            continue
        }
        if {[regexp $elem $line]} {
            set first_occurence($elem) 1
            puts $line
        }
    }
}
close $fp

参考:regexp

答案 1 :(得分:2)

package require fileutil

set queries {query1 query2 query3}
set result {}
::fileutil::foreachLine line file1.txt {
    foreach query $queries {
        if {![dict exists $result $query]} {
            if {[regexp $query $line]} {
                dict set result $query $line
                puts $line
            }
        }
    }
}

这里的技巧是将结果存储在字典中。如果已经存在与字典中的查询对应的值,则不再搜索它。这也具有以下优点:在搜索之后找到的行可用于脚本,并且不仅仅打印出来。 regexp搜索在该行的任何位置查找查询字符串:如果它只应位于该行的开头,请改用regexp ^$query $line

文档:dictfileutil包,foreachifpackageputsregexp,{{ 3}}

答案 2 :(得分:1)

试试这个,

set fd [open "query_file.txt" r]
set data [read $fd]
set uniq_list ""
foreach l [split $data "\n"] {
    lappend uniq_list [lindex $l 0]
}

set uniq_list [lsort -unique $uniq_list]

foreach l $uniq_list {
    if {[string equal $l ""]} {
        continue
    }
    foreach line [split $data "\n"] {
        if {[regexp $l $line]} {
            puts "$line"
            break
        }
    }
}

close $fd

参考文献:filelistregexp

答案 3 :(得分:1)

根本不使用regexp:我假设你的“查询”不包含空格

set list [list query1 query2 query3]
array set seen {}
set fh [open file1]
while {[gets $fh line] != -1} {
    set query [lindex [split $line] 0]
    if {$query in $list && $query ni [array names seen]} {
        set seen($query) 1
        puts $line
    }
}
query1 first data 
query2 another data  
query3 data something