Tcl / Expect正则表达式 - 想要变得懒惰(而不是贪婪)

时间:2013-10-04 03:26:32

标签: regex tcl expect non-greedy

网站新手,请耐心等待。我正在研究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

我的期望声明,使用regexp,如下:

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"

我希望比赛停在FIRST \ 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服务器上仅使用Basic Regular Expressions ...无法使用扩展正则表达式。

谢谢, 詹姆斯

2 个答案:

答案 0 :(得分:1)

哇,那太老了。 Almost 20 years old。你有可能升级吗?

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

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

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

在任何一种情况下,您都必须手动删除拖车回车。

答案 1 :(得分:1)

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 ......