关于Regex算法的问题(不一定与EXPECT相关)

Questions on Regex algorithm (not necessarily EXPECT related)

我正在尝试创建一个正则表达式来捕获我的设备的邻居详细信息(下面的示例输出)。

我可以对每一行进行硬编码,但我正在寻找更好的解决方案。也许学习一种新算法。

我对捕获设备 ID (HOST1)、接口 (GigabitEthernet0/1) 和端口 ID (GigabitEthernet2/43) 很感兴趣。对于每个邻居并将其存储在逗号分隔的列表中。

send "show cdp neighbors detail\r"
expect {

        -re "-+\r\nDevice ID: (\[^\r]+)\r\n\[^\r]+\r\n\[^\r]+\r\n\[^\r]+\r\nInterface: (\[^,]+),\[^:]+: (\[^\r]+)\r\n" {
                set neig $expect_out(1,string)
                set localint $expect_out(2,string)
                set rmint $expect_out(3,string)
                lappend neighbor "$neig,$localint,$rmint"
                exp_continue
        }
        "#" {}
}

NUMBER1#sho cdp neighbor detail
-------------------------
Device ID: HOST1
Entry address(es):
  IP address: 10.10.10.1
Platform: cisco WS-C6506-E,  Capabilities: Router Switch IGMP
Interface: GigabitEthernet0/1,  Port ID (outgoing port): GigabitEthernet2/43
Holdtime : 126 sec

Version :
Cisco IOS Software, s72033_rp Software (s72033_rp-ADVIPSERVICESK9_WAN-M), Version 12.2(33)SXJ8, RELEASE SOFTWARE (fc5)
Technical Support: http://www.cisco.com/techsupport
Copyright (c) 1986-2014 by Cisco Systems, Inc.
Compiled Thu 21-Aug-14 09:14 by prod_rel_team

advertisement version: 2
VTP Management Domain: 'ZONE'
Native VLAN: 3
Duplex: full
Management address(es):
  IP address: 10.10.10.1

-------------------------
Device ID: HOST2
Entry address(es):
  IP address: 10.10.10.2
Platform: cisco WS-C6506-E,  Capabilities: Router Switch IGMP
Interface: GigabitEthernet0/2,  Port ID (outgoing port): GigabitEthernet2/43
Holdtime : 139 sec

Version :
Cisco IOS Software, s72033_rp Software (s72033_rp-ADVIPSERVICESK9_WAN-M), Version 12.2(33)SXJ8, RELEASE SOFTWARE (fc5)
Technical Support: http://www.cisco.com/techsupport
Copyright (c) 1986-2014 by Cisco Systems, Inc.
Compiled Thu 21-Aug-14 09:14 by prod_rel_team

advertisement version: 2
VTP Management Domain: 'ZONE'
Native VLAN: 3
Duplex: full
Management address(es):
  IP address: 10.10.10.2

NUMBER1#

我上面的代码有效,只是在寻找更智能的代码?更轻松?或捕获数据的不同方式。而不是那个可怕的正则表达式。

foreach dev $neighbor {
        puts "$dev"
}
Output:
HOST1,GigabitEthernet0/1,GigabitEthernet2/43
HOST2,GigabitEthernet0/2,GigabitEthernet2/43

附带说明一下,如何在 expect 中使用“{}”匹配 "occurrences"? 例如:

-re "(\r\n\[^\r]+){3}"

将匹配 3 行

我认为最好使用更简单的匹配但使用更多的匹配子句。这往往会使代码更容易理解。

send "show cdp neighbors detail\r"
expect {
    -re {^Device ID: (\w+)} {
        set neig $expect_out(1,string)
        exp_continue
    }
    -re {^Interface: ([\w/]+), [^:]+: ([\w/]+)} {
        set localint $expect_out(1,string)
        set rmint $expect_out(2,string)
        lappend neighbor "$neig,$localint,$rmint"
        exp_continue
    }
    "#" {}
}

感兴趣的关键事物:

  • 我将 RE 放在大括号中,因此在正则表达式中几乎不需要那么多反斜杠。这对可读性有很大帮助!
  • 我正在使用 [\w/] 来匹配“单词字符”(基本上是字母数字)加上 /。如果没有前面的一点,那将是丑陋的。
  • ^ 锚定到行首。 ($到最后,但我们这里不需要它。)
  • 我假设每个设备(你关心的)都有一个 Device ID 行,后面跟着一个 Interface 行,允许我独立匹配这些行并只存储值在一个简单的变量中,以便在其他子句命中时将其拾取。这是使整体 RE 更简单的关键:我们不需要匹配所有内容,只需匹配我们真正感兴趣的位即可。

{3}(或更一般地 {3,42})确实匹配出现。它通常不是正确的工具,你需要非常小心你真正处理的是什么,但它确实有效。