Search code examples
pythonpyparsing

PyParsing: Parsing Cisco's "show ip bgp"


I am trying to parse a string as below using PyParsing.

R1# show ip bgp
BGP table version is 2, local router ID is 1.1.1.1
Status codes: s suppressed, d damped, h history, * valid, > best, i -     internal,
              r RIB-failure, S Stale
Origin codes: i - IGP, e - EGP, ? - incomplete

   Network          Next Hop            Metric LocPrf Weight Path
> 10.1.1.0/24      192.168.1.2              0             0 200 i

Note that LocPrf value is empty but it can be a number.

ipField = Word(nums, max=3)
ipAddr = Combine(ipField + "." + ipField + "." + ipField + "." + ipField)
status_code = Combine(Optional(oneOf("s d h * r")) + ">" + Optional(Literal("i"))
prefix = Combine(ipAddr + Optional(Literal("/") + Word(nums,max=2)))
next_hop = ipAddr
med = Word(nums)
local_pref = Word(nums) | White()
path = Group(OneOrMore(Word(nums)))
origin = oneOf("i e ?")

This is the grammar.

g = status_code + prefix + next_hop + med + local_pref + Suppress(Word(nums)) + Optional(path) + origin

I just need to parse the Bold line. But this is not parsing it properly. It assigns Weight value to LocPrf.


Solution

  • Please look over the following code example (which I will include in the next pyparsing release). You should be able to adapt it to your application:

    from pyparsing import col,Word,Optional,alphas,nums,ParseException
    
    table = """\
    12345678901234567890
    COLOR      S   M   L
    RED       10   2   2
    BLUE           5  10
    GREEN      3       5
    PURPLE     8"""
    
    # function to create column-specific parse actions
    def mustMatchCols(startloc,endloc):
        def pa(s,l,t):
            if not startloc <= col(l,s) <= endloc:
                raise ParseException(s,l,"text not in expected columns")
        return pa
    
    # helper to define values in a space-delimited table
    def tableValue(expr, colstart, colend):
        return Optional(expr.copy().addParseAction(mustMatchCols(colstart,colend)))
    
    
    # define the grammar for this simple table
    colorname = Word(alphas)
    integer = Word(nums).setParseAction(lambda t: int(t[0])).setName("integer")
    row = (colorname("name") + 
            tableValue(integer, 11, 12)("S") + 
            tableValue(integer, 15, 16)("M") + 
            tableValue(integer, 19, 20)("L"))
    
    # parse the sample text - skip over the header and counter lines
    for line in table.splitlines()[2:]:
        print
        print line
        print row.parseString(line).dump()