【问题标题】:How to use regexp to search a list for a string using proc?如何使用正则表达式使用 proc 在列表中搜索字符串?
【发布时间】:2014-10-26 21:22:38
【问题描述】:

尝试深入研究 TcL 脚本。我发现我正在编写很多重复的代码,我想弄清楚如何使它成为一个过程,以缩短我的脚本。我对整个过程的想法可能是错误的。我目前正在复制 foreach 循环并更改变量的名称。我可以通过一个进程来执行此操作,以便我只键入一次 foreach 循环吗?

一个例子是,我需要一个过程来搜索列表中“应该”存在的字符串。如果他们不在那里,我想输出到报告文件。

如果不清楚,我深表歉意:

类似的东西 设置强制全局“{ ^service tcp-keepalives-in} { ^service tcp-keepalives-out} { ^service timestamps debug datetime msec}"

    set run "{
    version 12.4} 
    {service timestamps debug datetime msec} 
    {service timestamps log datetime msec}
    "

    proc mandatory {mandatoryList config} {
        foreach command $mandatoryList {
            set x 1
            foreach line $config {
                if {![regexp $command $line]} {
                    incr x
                }
            }
            if {$x>[llength $config]} {
                append report $command\n
                return $command\n
            }
        }
    }

    mandatory $mandatoryGlobal $run

    puts $report
    #I would expect that report shows 
    #^service tcp-keepalives-in
    #^service tcp-keepalives-out

    #But I only have this????
    #^service tcp-keepalives-in

    #If I run the foreach loop without the proc & change the variables, 
    #it works as expected

此外,我已对其进行了编辑,以便更清楚地了解我想要做什么。在我重新阅读我的问题后,Donal Fellows 的回答完美,但我的目标并不清楚。多纳尔,我真的很感谢你的努力和一个惊人的解释。

【问题讨论】:

  • 你不需要set y,你可以直接使用mandatory $value $run。但是,如果多纳尔没有回答,您将不得不更好地解释您的其他问题。
  • 看起来必须使用 lsearch。类似foreach value $mandatoryValues { if {[lsearch -regexp $list $value] == -1} {...} }
  • string map {process procedure} $question
  • 我正在寻找的是类似于 Jerry 所写的内容,但我希望能够更改变量,因此我不会重新编写循环。我真的才刚刚开始编程,所以如果我不清楚我的目标,请原谅我。这是我所做的一个示例,但我正在重写列表的不同部分的相同代码。附加报告“在配置中找不到强制命令\n” foreach 命令 $mandatoryGlobal { set x 1 foreach line $run { if {![regexp $command $line]} { incr x } } if {$x>[llength $run ]} { 追加报告 $command\n } }

标签: regex tcl proc


【解决方案1】:

好的,你有一个单词列表和一个字符串来查找它们。让我们假设这些词都表现良好(没有 RE 元字符),所以我们可以简单地搜索,并且字符串也只包含简单的词。

那么,在这种情况下,我们可以使用foreach 来检查单词列表,并使用lsearch 而不是regexp 来查看单词是否存在:

proc mandatory {string list} {
    set report {}
    foreach word $list {
        if {[lsearch -exact $string $word] < 0} {
            lappend report $word
        }
    }
    return $report
}

现在我们需要调用它并处理结果:

set run "this is a test list to check for a string"
set value "string that's not in the list"
set unfound [mandatory $value $run]
if {[llength $unfound] > 0} {
    puts "The following words were not in the string: $unfound"
} else {
    puts "All words present and correct"
}

请注意,我们将未找到的单词列表作为值返回,将其存储在局部变量中,然后生成消息。 (llength 检查是查看列表是否为空的好方法。)


我们可以使用ni (Not In) 运算符缩短mandatory 过程:

proc mandatory {string list} {
    set report {}
    foreach word $list {
        if {$word ni $string} {
            lappend report $word
        }
    }
    return $report
}

但是我们应该更加注意出现的单词。这是我们使用正则表达式的地方;解析:

proc mandatory {string list} {
    set report {}
    set stringWords [regexp -all -inline {\S+} $string]
    foreach word $list {
        if {$word ni $stringWords} {
            lappend report $word
        }
    }
    return $report
}

在某些情况下,最好为存在的单词构建一个哈希表,这样我们就不会一遍又一遍地对字符串的单词进行线性扫描。 Tcl 数组实际上是哈希表。

proc mandatory {string list} {
    set report {}
    foreach word [regexp -all -inline {\S+} $string] {
        set present($word) "some dummy value"
    }
    foreach word $list {
        if {![info exists present($word)]} {
            lappend report $word
        }
    }
    return $report
}

(不要担心这会有点长;除了 RE 拆分器之外,它都是字节码编译的,坦率地说,它不需要。)

您可以编写一些东西来使用正则表达式进行实际搜索(lsearch -regexp 是您要查找的键),但我不建议您这样做,除非您真的需要它:对于这种“检查所有这些事物存在”,它们是错误的工具。

【讨论】:

  • Donal,我已经回复您的回答,并意识到我的逻辑有误。你100%回答了我的意图。我使用的是 TcL 8.3 版,所以我没有你使用的一些方便的命令,比如“ni”。我继续你的第一个例子。我正在使用 lsearch -regexp,因为我必须能够区分 {ip http server} 和 {no ip http server} 之类的东西。非常感谢您的解释。
猜你喜欢
  • 1970-01-01
  • 2019-10-17
  • 2017-06-15
  • 2014-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多