【问题标题】:Tcl/Expect regular expression - want to make lazy (as opposed to greedy)Tcl/Expect 正则表达式 - 想要变得懒惰(而不是贪婪)
【发布时间】:2013-10-04 03:26:32
【问题描述】:

网站新手,请多多包涵。我正在处理 Tcl/Expect 脚本并尝试匹配以下路由器输出中第 4 行的一部分(显示了两个可能的输出)。它通常有一个 IP 地址,但也可能有第二个示例中的字符串:

Routing entry for 10.1.1.0/30
  Known via "static", distance 1, metric 0
  Routing Descriptor Blocks:
  * 10.3.3.1
      Route metric is 0, traffic share count is 1

另一个可能的输出:

Routing entry for 10.1.2.0/24
  Known via "static", distance 220, metric 0 (connected)
  Advertised by bgp 1234
  Routing Descriptor Blocks:
  * directly connected, via Null0
      Route metric is 0, traffic share count is 1

我的期望语句,使用正则表达式,如下:

expect -re "Routing Descriptor Blocks:\r\n  \\\* (.*)\r\n" {
        set next_hop $expect_out(1,string)
        puts "\n\n*Next-hop address is: $next_hop*\n"
}

(这 3 个反斜杠是为了让它们通过 Tcl 解析,并且将 * 传递给正则表达式解释器,以匹配文字星号。)

我的问题是 - 毫不奇怪 - 这是一个“贪婪”匹配,我需要它不要贪婪。请参阅调试输出,其中清楚地说明了这一点:

expect: does "show ip route 10.1.1.0\r\nRouting entry for 10.1.1.0/30\r\n  Known via "static", distance 1, metric 0\r\n  Routing Descriptor Blocks:\r\n  * 10.3.3.1\r\n      Route metric is 0, traffic share count is 1\r\n\r\nRouter>" (spawn_id 4) match regular expression "Routing Descriptor Blocks:\r\n  \* (.*)\r\n"? yes
expect: set expect_out(0,string) "Routing Descriptor Blocks:\r\n  * 10.3.3.1\r\n   Route metric is 0, traffic share count is 1\r\n\r\n"
expect: set expect_out(1,string) "10.3.3.1\r\n      Route metric is 0, traffic share count is 1\r\n"

我希望比赛在第一个 \r\n 停止。

所以,对于非贪婪匹配,我会认为我需要添加一个“?”如下:

expect -re "Routing Descriptor Blocks:\r\n  \\\* (.*?)\r\n" {
        set next_hop $expect_out(1,string)
        puts "\n\n*Next-hop address is: $next_hop*\n"
}

问题是,这似乎不起作用。我从调试输出中得到以下信息:

bad regular expression: nested *?+
    while executing
"expect -re "Routing Descriptor Blocks:\r\n  \\\* (.*?)\r\n" {
        set next_hop $expect_out(1,string)
        puts "\n\n*Next-hop address is: $next_hop*\n"
}"
    (file "./test_telnet_to_router.exp" line 23)

我已经盯着这个太久了,所以我想我会请求一些帮助。关于我需要做些什么来获得我需要的懒惰匹配的任何想法?请注意,我坚持在此 HP-UX 服务器上仅使用基本正则表达式...扩展正则表达式不可用。

谢谢, 詹姆斯

【问题讨论】:

  • 这是什么 Tcl 版本? (在交互式期望或 tclsh 会话中,info patchlevel
  • expect1.1> info patchlevel 7.4 感谢您抽出宝贵时间查看此内容!

标签: regex tcl expect non-greedy


【解决方案1】:

哇,那是旧的。 Almost 20 years old。有可能升级吗?

进行惰性匹配的一种方法是搜索不是特定字符的贪婪字符序列。这可能有效

-re "Routing Descriptor Blocks:\r\n  \\\* (\[^\n\]+)\n"

另一种选择是进行贪婪匹配,然后在换行符上拆分捕获的部分。

无论哪种情况,您都必须手动删除尾随回车。

【讨论】:

  • 成功了,谢谢。现在,我无法使用string trimright $next_hop 甚至string trimright $next_hop "\r" 删除尾随回车,这让我感到很困惑。我检查了与 Tcl 7.5 一样古老的文档,并且 string trimright 命令似乎已经存在了一段时间......有什么想法吗?当我打印出我的变量时,尾随回车仍然存在。
  • 嗯。如果你知道那里有 CR,你可以使用(深呼吸)[string range $next_hop 0 [expr {[string length $next_hop] - 2}]]
  • 误报!我在其他地方做错了什么。 string trimright 实际上正在工作,但我没有在打印之前保存修剪后的版本……我猜是我的 Perl 过去。我现在都准备好了。非常感谢您的帮助。
  • 啊。采用变量 value 的 Tcl 命令不能修改变量本身(即,string 命令、linsertjoin 等)——这些命令返回的值必须保存.采用变量 name 可以 修改变量内容的 Tcl 命令(即lappendappendincr
【解决方案2】:

Tcl 7.4 是过去的真正爆炸,它使用了一个(非常旧的)版本的 RE 引擎,根本不支持非贪婪的 RE。 (RE 引擎的变化发生在 Tcl 8.0 中,现在仍然有十多年的历史了。而且很长一段时间都不支持了……)

解决该问题的最简单机制是在正则表达式中更具体地说明要匹配的内容。特别是,如果您不希望在捕获的部分中匹配换行符,请不要使用(.*),而是使用([^\n]*)。由于您将 RE 放在双引号中,因此您实际上需要使用它:

expect -re "Routing Descriptor Blocks:\r\n  \\* (\[^\n\]*)\r\n" {
    set next_hop $expect_out(1,string)
    puts "\n\n*Next-hop address is: $next_hop*\n"
}

这一切都假设您不想要Route metric… 行。如果您确实想要它,最简单的捕获方法是在末尾添加另一个(无换行符捕获)RE,使其最终成为$expect_out(2,string)

expect -re "Routing Descriptor Blocks:\r\n  \\* (\[^\n\]*)\r\n *(\[^\n\]*)\r\n" {
    set next_hop $expect_out(1,string)
    puts "\n\n*Next-hop address is: $next_hop*\n"
    puts "Extra info: $expect_out(2,string)"
}

一般来说,在使用 Expect 时,请尽量使用您的 RE。它有助于。但也请记住,您可以同时期待几个不同的 RE……

【讨论】:

  • 你说得对,这是老东西......这些家伙将“如果它有效,请不要碰它”的方法更上一层楼。不幸的是,对此无能为力。您的 [first] 建议效果很好,谢谢(我不需要 Route 指标...行)。现在我正在努力删除尾随的 \r,正如您可能从我对第一个答案的评论中看到的那样。
  • @James 我不太了解expect 或旧版本的Tcl,但是如果你使用正则表达式\[^\n\r\]* 而不是\[^\n\]*,你会得到回车吗?
  • 谢谢,@Jerry... 我试过了,但不匹配。但是我现在已经准备好了(请参阅我对上述答案的 cmets)。感谢您的参与!
  • @James 哦,好吧。很高兴你解开了这个谜=P
猜你喜欢
  • 2012-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-11
  • 2023-03-12
  • 2011-01-19
相关资源
最近更新 更多