Regexp解决方案列表

时间:2016-12-30 13:07:13

标签: regex tcl

我无法在regexp之后找到它, SCRIPT1:

set name_list {{Avg Speed} {Total Time(hr) }}
set lines {{Avg Speed|0.000} {Total Time(hr)|NA} }

set line_number 0
foreach line $lines {
    incr line_number

    foreach name $name_list {
        puts "flag1: $name"
        if { [regexp "^$name\\|(.+)$" $line matchVar value ] } {
            puts "flag4: $value"
            set rval($name) $value
            set rval($name,line) $line_number
        }
    }
}

输出类似于:
输出1:

    flag1: Avg Speed
    flag4: 0.000
    flag1: Total Time(hr) 
    flag1: Avg Speed
    flag1: Total Time(hr)

如果我改变前2行,如:
SCRIPT2(修改):

set name_list {{Avg Speed} {Total Time}}
set lines {{Avg Speed|0.000} {Total Time|NA} }

我得到的是这样的:
Output2(想要输出像这样 - 实际输出)

   flag1: Avg Speed
   flag4: 0.000
   flag1: Total Time
   flag1: Avg Speed
   flag1: Total Time
   flag4: NA

那么,我应该如何修改我的正则表达式,以便我得到"(hr)"在第一个脚本中的output1 flag4处打印?

regexp "^$name\\|(.+)$" $line matchVar value       

matchVar的目的是什么,因为这里匹配" 0.000& NA",但是怎么样?

2 个答案:

答案 0 :(得分:1)

这是你的问题:你正在使用正则表达式,其中一个简单的字符串比较是合适的:

set name_list {{Avg Speed} {Total Time(hr)}}      ;# <- note that I've shaved off space
set lines {{Avg Speed|0.000} {Total Time(hr)|NA}}

set line_number 0
foreach line $lines {
    incr line_number

    foreach name $name_list {
        puts "flag1: $name"
        lassign [split $line |] _name value
        if {$_name eq $name} {
            puts "flag4: $value"
            set rval($name) $value
            set rval($name,line) $line_number
        }
    }
}

文档: eq (operator)foreachifincrlassignputssetsplit

答案 1 :(得分:1)

matchVar的目的是捕获RE匹配的整个子字符串;当你在两端锚定RE时,它与输入字符串相同(如果RE完全匹配)并且可能被忽略。当您的RE未经锚定或仅锚定在一侧时,当整体匹配(子)字符串为您提供有用信息时,它会更加相关。

你真正的问题是,你注入要搜索的RE的字符串本身有RE元字符; (hr)被视为匹配hr的子RE,并将其显示为regexp可以报告的子匹配部分之一。要解决这个问题,我们需要在替换前向RE元字符添加反斜杠。我们可以使用regsub -all来做到这一点,因为RE子语言保证所有元字符都不是字母数字“单词”字符,并且可以通过在它们前面加一个反斜杠来安全引用。

# ...
foreach name $name_list {
    puts "flag1: $name"
    # Replace all non-word characters with their backslashed form
    regsub -all {\W} $name {\\&} REname
    if { [regexp "^$REname\\|(.+)$" $line matchVar value ] } {
        # ...