Finditer function#

Function finditer:

  • is used to search for all non-overlapping matches in string

  • returns an iterator with Match objects

  • finditer returns iterator even if no match is found

Function finditer is well suited to handle those commands whose output is displayed by columns. For example: ‘sh ip int br’, ‘sh mac address-table’, etc. In this case it can be applied to the entire output of command.

Example of ‘sh ip int br’ output:

In [8]: sh_ip_int_br = '''
   ...: R1#show ip interface brief
   ...: Interface             IP-Address      OK? Method Status           Protocol
   ...: FastEthernet0/0       YES manual up               up
   ...: FastEthernet0/1       YES manual up               up
   ...: FastEthernet0/2       YES manual up               up
   ...: FastEthernet0/3       unassigned      YES unset  up               up
   ...: Loopback0           YES manual up               up
   ...: Loopback100        YES manual up               up
   ...: '''

regex for output processing:

In [9]: result = re.finditer(r'(\S+) +'
   ...:                      r'([\d.]+) +'
   ...:                      r'\w+ +\w+ +'
   ...:                      r'(up|down|administratively down) +'
   ...:                      r'(up|down)',
   ...:                      sh_ip_int_br)

result variable contains an iterator:

In [12]: result
Out[12]: <callable_iterator at 0xb583f46c>

Iterator contains Match objects:

In [16]: groups = []

In [18]: for match in result:
    ...:     print(match)
    ...:     groups.append(match.groups())
<_sre.SRE_Match object; span=(103, 171), match='FastEthernet0/0       YES manual >
<_sre.SRE_Match object; span=(172, 240), match='FastEthernet0/1       YES manual >
<_sre.SRE_Match object; span=(241, 309), match='FastEthernet0/2       YES manual >
<_sre.SRE_Match object; span=(379, 447), match='Loopback0           YES manual >
<_sre.SRE_Match object; span=(448, 516), match='Loopback100        YES manual >'

Now in groups list there are tuples with strings that fallen into groups:

In [19]: groups
[('FastEthernet0/0', '', 'up', 'up'),
 ('FastEthernet0/1', '', 'up', 'up'),
 ('FastEthernet0/2', '', 'up', 'up'),
 ('Loopback0', '', 'up', 'up'),
 ('Loopback100', '', 'up', 'up')]

A similar result can be obtained by a list comprehension:

In [20]: regex = r'(\S+) +([\d.]+) +\w+ +\w+ +(up|down|administratively down) +(up|down)'

In [21]: result = [match.groups() for match in re.finditer(regex, sh_ip_int_br)]

In [22]: result
[('FastEthernet0/0', '', 'up', 'up'),
 ('FastEthernet0/1', '', 'up', 'up'),
 ('FastEthernet0/2', '', 'up', 'up'),
 ('Loopback0', '', 'up', 'up'),
 ('Loopback100', '', 'up', 'up')]

Now we will analyze the same log file that was used in search and match subsections.

In this case it is possible to pass the entire contents of file (

import re

regex = (r'Host \S+ '
         r'in vlan (\d+) '
         r'is flapping between port '
         r'(\S+) and port (\S+)')

ports = set()

with open('log.txt') as f:
    for m in re.finditer(regex,
        vlan =

print('Loop between ports {} in VLAN {}'.format(', '.join(ports), vlan))


In real life, a log file can be very large. In that case, it’s better to process it line by line.

Output will be the same:

$ python
Loop between ports Gi0/19, Gi0/24, Gi0/16 в VLAN 10

Processing of ‘show cdp neighbors detail’ output#

finditer can handle output of ‘sh cdp neighbors detail’ as well as in subsection.

The script is almost identical to version with ( file):

import re
from pprint import pprint

def parse_cdp(filename):
    regex = (r'Device ID: (?P<device>\S+)'
             r'|IP address: (?P<ip>\S+)'
             r'|Platform: (?P<platform>\S+ \S+),'
             r'|Cisco IOS Software, (?P<ios>.+), RELEASE')

    result = {}

    with open(filename) as f:
        match_iter = re.finditer(regex,
        for match in match_iter:
            if match.lastgroup == 'device':
                device =
                result[device] = {}
            elif device:
                result[device][match.lastgroup] =

    return result


Now matches are searched throughout the file, not in every line separately:

with open(filename) as f:
    match_iter = re.finditer(regex,

Then matches go through the loop:

with open(filename) as f:
    match_iter = re.finditer(regex,
    for match in match_iter:

The rest is the same.

The result will be:

$ python
{'R1': {'ios': '3800 Software (C3825-ADVENTERPRISEK9-M), Version 12.4(24)T1',
        'ip': '',
        'platform': 'Cisco 3825'},
 'R2': {'ios': '2900 Software (C3825-ADVENTERPRISEK9-M), Version 15.2(2)T1',
        'ip': '',
        'platform': 'Cisco 2911'},
 'SW2': {'ios': 'C2960 Software (C2960-LANBASEK9-M), Version 12.2(55)SE9',
         'ip': '',
         'platform': 'cisco WS-C2960-8TC-L'}}

Although the result is similar, finditer has more features, as you can specify not only what should be in searched string but also in strings around it. For example, you can specify exactly which IP address to take:

Device ID: SW2
Entry address(es):
  IP address:
Platform: cisco WS-C2960-8TC-L,  Capabilities: Switch IGMP


Native VLAN: 1
Duplex: full
Management address(es):
  IP address:

If you want to take the first IP address you can supplement a regex like this:

regex = (r'Device ID: (?P<device>\S+)'
         r'|Entry address.*\n +IP address: (?P<ip>\S+)'
         r'|Platform: (?P<platform>\S+ \S+),'
         r'|Cisco IOS Software, (?P<ios>.+), RELEASE')