Regex слишком "жадный", как это исправить

Рейтинг: -1Ответов: 2Опубликовано: 29.05.2023

необходимо из вывода подобно этому:

VID  Type    Ports
--------------------------------------------------------------------------------
1    common  UT:GE0/0/15(D)     GE0/0/16(D)     GE0/0/18(D)     GE0/0/19(D)
                GE0/0/21(D)     XGE0/0/1(D)     XGE0/0/2(D)     XGE0/0/3(D)
                XGE0/0/4(D)
             TG:GE0/0/24(U)
3    common  UT:GE0/0/14(U)     GE0/0/22(U)     GE0/0/24(U)
             TG:XGE0/0/1(D)     XGE0/0/2(D)
6    common  UT:GE0/0/17(U)     GE0/0/20(U)
             TG:GE0/0/24(U)     XGE0/0/1(D)     XGE0/0/2(D)
12   common  TG:GE0/0/24(U)     XGE0/0/1(D)     XGE0/0/2(D)
105  common  TG:GE0/0/24(U)     XGE0/0/1(D)     XGE0/0/2(D)
107  common  TG:GE0/0/24(U)     XGE0/0/1(D)     XGE0/0/2(D)
888  common  UT:GE0/0/1(D)      GE0/0/2(D)      GE0/0/3(D)      GE0/0/4(D)
                GE0/0/5(D)      GE0/0/6(D)      GE0/0/7(D)      GE0/0/8(D)
                GE0/0/9(D)      GE0/0/10(D)     GE0/0/11(D)     GE0/0/12(D)
                GE0/0/13(D)
             TG:GE0/0/24(U)     XGE0/0/1(D)     XGE0/0/2(D)

VID  Status  Property      MAC-LRN Statistics Description

получить имена всех untagged интерфейсов 888 VLAN (все что между UT:и TG:) если я пишу:

r'^888\s+common\s+UT:(.+)(?=\([U|D]\)\s*).+TG:'

возвращаются все интерфейсы от первого до последнего если

r'^888\s+common\s+UT:(.*?)(?=\([U|D]\)\s*).+TG:'

то только первый GE0/0/1. как написать выражение чтобы вернуло все GE..... без (D)

ссылка на regex

Ответы

▲ 1

Если у вас нет явного шаблона, то не следует все решать одним регекспом

import re
data = '''
VID  Type    Ports
--------------------------------------------------------------------------------
1    common  UT:GE0/0/15(D)     GE0/0/16(D)     GE0/0/18(D)     GE0/0/19(D)
                GE0/0/21(D)     XGE0/0/1(D)     XGE0/0/2(D)     XGE0/0/3(D)
                XGE0/0/4(D)
             TG:GE0/0/24(U)
3    common  UT:GE0/0/14(U)     GE0/0/22(U)     GE0/0/24(U)
             TG:XGE0/0/1(D)     XGE0/0/2(D)
6    common  UT:GE0/0/17(U)     GE0/0/20(U)
             TG:GE0/0/24(U)     XGE0/0/1(D)     XGE0/0/2(D)
12   common  TG:GE0/0/24(U)     XGE0/0/1(D)     XGE0/0/2(D)
105  common  TG:GE0/0/24(U)     XGE0/0/1(D)     XGE0/0/2(D)
107  common  TG:GE0/0/24(U)     XGE0/0/1(D)     XGE0/0/2(D)
888  common  UT:GE0/0/1(D)      GE0/0/2(D)      GE0/0/3(D)      GE0/0/4(D)
                GE0/0/5(D)      GE0/0/6(D)      GE0/0/7(D)      GE0/0/8(D)
                GE0/0/9(D)      GE0/0/10(D)     GE0/0/11(D)     GE0/0/12(D)
                GE0/0/13(D)
             TG:GE0/0/24(U)     XGE0/0/1(D)     XGE0/0/2(D)

VID  Status  Property      MAC-LRN Statistics Description
'''
finds = " ".join(data.split("\n")[3:-3])
finds = re.findall(r"UT:(.*?)TG:", finds)
res = []
[res.extend(x.split()) for x in finds]
print(res)
['GE0/0/15(D)', 'GE0/0/16(D)', 'GE0/0/18(D)', 'GE0/0/19(D)', 'GE0/0/21(D)',
 'XGE0/0/1(D)', 'XGE0/0/2(D)', 'XGE0/0/3(D)', 'XGE0/0/4(D)', 'GE0/0/14(U)', 
'GE0/0/22(U)', 'GE0/0/24(U)', 'GE0/0/17(U)', 'GE0/0/20(U)', 'GE0/0/1(D)', 
'GE0/0/2(D)', 'GE0/0/3(D)', 'GE0/0/4(D)', 'GE0/0/5(D)', 'GE0/0/6(D)', 
'GE0/0/7(D)', 'GE0/0/8(D)', 'GE0/0/9(D)', 'GE0/0/10(D)', 'GE0/0/11(D)', 
'GE0/0/12(D)', 'GE0/0/13(D)']

▲ 0

я знал что сюда просится textFSM, но не представлял как написать шаблон. задал гуглу правильный вопрос и получил пример. решается все гораздо проще huawei_int_by_vlan.template:

Value List INTF (\w+\d\/\d\/\d+)

Start
  ^\s+TG: -> Continue.Record
  ^888\s+common\s+UT:${INTF}\( -> Continue
  ^888\s+common\s+UT:\S+\s+${INTF}\( -> Continue
  ^888\s+common\s+UT:\S+\s+\S+\s+${INTF}\( -> Continue
  ^888\s+common\s+UT:\S+\s+\S+\s+\S+\s+${INTF}\( -> Continue
  ^\s+${INTF}\( -> Continue
  ^\s+\S+\s+${INTF}\( -> Continue
  ^\s+\S+\s+\S+\s+${INTF}\( -> Continue
  ^\s+\S+\s+\S+\s+\S+\s+${INTF}\( -> Continue

и тогда

def proba():
    data = '''
    dis vlan | beg 888
    The total number of VLANs is: 7
    --------------------------------------------------------------------------------
    U: Up;         D: Down;         TG: Tagged;         UT: Untagged;
    MP: Vlan-mapping;               ST: Vlan-stacking;
    #: ProtocolTransparent-vlan;    *: Management-vlan;
    --------------------------------------------------------------------------------
   
    VID  Type    Ports
    --------------------------------------------------------------------------------
    888  common  UT:GE0/0/1(D)      GE0/0/2(D)      GE0/0/3(D)      GE0/0/4(D)
                    GE0/0/5(D)      GE0/0/6(D)      GE0/0/7(D)      GE0/0/8(D)
                    GE0/0/9(D)      GE0/0/10(D)     GE0/0/11(D)     GE0/0/12(D)
                    GE0/0/13(D)
                 TG:GE0/0/24(U)     XGE0/0/1(D)     XGE0/0/2(D)
   
    VID  Status  Property      MAC-LRN Statistics Description
    --------------------------------------------------------------------------------
    1    enable  default       enable  disable    VLAN 0001
    3    enable  default       enable  disable    VLAN 0003
    6    enable  default       enable  disable    VLAN 0006
    12   enable  default       enable  disable    VLAN 0012
    105  enable  default       enable  disable    VLAN 0105
    107  enable  default       enable  disable    VLAN 0107
    888  enable  default       enable  disable    VLAN 0888
    '''
    tf = myini.templpath + 'huawei_int_by_vlan.template'
    with open(tf) as tmpl:
        fsm = textfsm.TextFSM(tmpl)
        result = fsm.ParseText(data)
    print(result)

возвращает:

[[['GE0/0/2', 'GE0/0/5', 'GE0/0/6', 'GE0/0/7', 'GE0/0/8', 'GE0/0/9', 'GE0/0/10', 'GE0/0/11', 'GE0/0/12', 'GE0/0/13']], [['XGE0/0/1', 'XGE0/0/2']]]

мне с шаблоном удобно, в зависимости от бренда (циско, хуавей) просто буду давать разные команды и разные шаблоны использовать а код унифицируется