正则表达式中的可变匹配数

时间:2014-01-31 18:38:50

标签: regex string tcl

我有这个文件:

#2/1/1/21=p1 5/1/1/21=p1 isid=104
3/1/1/9=p1 4/1/1/4=p1 5/1/1/17=p1 6/1/1/4=p1 isid=100
1/1/1/4=p1 6/1/1/5=p1 isid=101

我希望忽略第1行(它是注释行) 在第二行我想在三个变量var1 var2和var3中得到“3/1/1/9”“4/1/1/4”“5/1/1/17” 在第三行中,我想在两个变量var1和var2中得到“1/1/1/4”和“6/1/1/5”。

目前我可以忽略第1行,并在第2行或第3行匹配我想要的内容:

if {[regexp {^(\d/\d/\d/\d{1,2})=p1.*(\d/\d/\d/\d{1,2})=p1} $line value match1 match2]} {  
    # This works for line 3 but not line 2
}

 if {[regexp {^(\d/\d/\d/\d{1,2})=p1.*(\d/\d/\d/\d{1,2})=p1.*(\d/\d/\d/\d{1,2})=p1} $line value match1 match2 match3]} {  
    # This works for line 2 but not line 3
}

如何为第2行和第3行匹配正确的数量?

3 个答案:

答案 0 :(得分:2)

试试这个正则表达式:

[regexp {^(\d/\d/\d/\d{1,2})=p1.*?(\d/\d/\d/\d{1,2})=p1(?:.*?(\d/\d/\d/\d{1,2})=p1)?} $line value match1 match2 match3]
                                                       ^^^                        ^^

这使得第三场比赛可选。

我也将你贪婪的.*变成了非贪婪的.*?


要获得所有匹配,您可以使用更像这样的内容:

if {[string range $line 0 0] ne "#"} {
    set matches [regexp -all -inline -- {\d/\d/\d/\d{1,2}(?==p1)} $line]
}

您将获得列表$matches中的匹配项。然后,您可以通过lindexlassign访问它们,并为其指定具体名称。

答案 1 :(得分:1)

这可能会更好:

lassign [regexp -all -inline {\d+(?:/\d+){3}(?==p1)} $line] var1 var2 var3

如果只有2个匹配,则var3将为空

如果有更多匹配,则只会在变量中捕获前3个。

如果你真的只想要所有的比赛:

set vars [regexp -all -inline {\d+(?:/\d+){3}(?==p1)} $line]

忽略评论:

while {[gets $fh line] != -1} {
    if {[regexp {^\s*#} $line]} continue

    # do your other stuff here ...
}

答案 2 :(得分:0)

试试这个:

(^|\s)(\d/\d/\d/\d=p1)

或更紧凑:

(^|\s)((\d/){3}\d=p1)