регулярное выражение с 'Named Capture Group', чтобы поймать образец или альтернативный - PullRequest
1 голос
/ 16 февраля 2020

Я пытаюсь поймать с помощью одного уникального регулярного выражения

either: ' PIC S9(17).'            # with 'S9(17)'      in Named Capture Group pic
either: ' PIC S9(13)V9(2).'       # with 'S9(13)V9(2)' in Named Capture Group pic
either: ' PIC S9(9)V9(2) COMP-3.' # with 'S9(9)V9(2)'  in Named Capture Group pic
either: ' PIC X(16).'             # with 'X(16)'       in Named Capture Group pic

с помощью r'\s*PIC\s+(?P<pic>\S+)' Я ловлю все, кроме 'PI C S9 (9) V9 (2) COMP-3.'

с r'\s*PIC\s+(?P<pic>\S+) COMP-3' Я ловлю только 'PI C S9 (9) V9 (2) COMP-3.'

Это мой Python код:

import re
def get_pics(data, pic):
    base = r'^(?P<level>\d{2})\s+(?P<name>\S+)'
    end = r'\.$'
    pformat = "({})?"
    pattern = re.compile(base + pformat.format(pic) + end)

    for row in data.strip().split('\n'):
        re_match = pattern.match(row.strip())
        if not re_match:
            print(' => NOP:\n    ', row)
        else:
            match = re_match.groupdict()
            print('ok:', match)

data = """
   12 M-AR03-MONTANT-RDJ                 PIC S9(17).
   12 M-AR03-COMPTE-RDJ                  PIC X(8).
  09 M-N014-INC-CHARG-AMT-FSOL           PIC S9(9)V9(2) COMP-3.
  09 M-N014-CHARGE-TYPE-FSOL             PIC X(5).
"""

Итак, мы получаем:

>>> get_pics(data, r'\s*PIC\s+(?P<pic>\S+)')
ok: {'level': '12', 'name': 'M-AR03-MONTANT-RDJ', 'pic': 'S9(17)'}
ok: {'level': '12', 'name': 'M-AR03-COMPTE-RDJ', 'pic': 'X(8)'}
 => NOP:
       09 M-N014-INC-CHARG-AMT-FSOL  PIC S9(9)V9(2) COMP-3.
ok: {'level': '09', 'name': 'M-N014-CHARGE-TYPE-FSOL', 'pic': 'X(5)'}
>>>

или

>>> get_pics(data, r'\s*PIC\s+(?P<pic>\S+) COMP-3')
 => NOP:
     12 M-AR03-MONTANT-RDJ         PIC S9(17).
 => NOP:
        12 M-AR03-COMPTE-RDJ       PIC X(8).
ok: {'level': '09', 'name': 'M-N014-INC-CHARG-AMT-FSOL', 'pic': 'S9(9)V9(2)'}
 => NOP:
       09 M-N014-CHARGE-TYPE-FSOL  PIC X(5).
>>>

Странно то, что в https://regex101.com/ '\s*PIC\s+(?P<pic>\S+)' совпадают все 4 строки:

PIC S9(17).
PIC S9(13)V9(2).
PIC S9(9)V9(2) COMP-3.
PIC X(16).

Если я попробую регулярное выражение @ the четвертая птица, я получу:

In [2]: get_pics(data, r'\bPIC (?P<pic>(?:[A-Z]\d*\(\d+\))+)[^.\r\n]*\.') 
   ...:                                                                                                                            
 => NOP:
     12 M-AR03-MONTANT-RDJ          PIC S9(17).
 => NOP:
        12 M-AR03-COMPTE-RDJ           PIC X(8).
 => NOP:
       09 M-N014-INC-CHARG-AMT-FSOL    PIC S9(9)V9(2) COMP-3.
 => NOP:
       09 M-N014-CHARGE-TYPE-FSOL      PIC X(5).

In [3]:    

Ответы [ 3 ]

2 голосов
/ 16 февраля 2020

Если вы хотите захватить группу pic с этими значениями, и в конце должна быть точка в точке, вы можете сделать шаблон немного более конкретным c:

\bPIC (?P<pic>(?:[A-Z]\d*\(\d+\))+)[^.\r\n]*\.
  • \bPIC Граница слова, совпадение PIC и пробел
  • (?P<pic> Именованная группа pic
    • (?: Нефиксированная группа
      • [A-Z]\d*\(\d+\) Соответствие символу AZ, опитальные цифры и 1+ цифры в скобках
    • )+ Закрыть группу, повторить 1+ раз
  • ) Закрыть группу pic
  • [^.\r\n]*\. Совпадение с любым символом, кроме точки и новой строки 0+ раз и совпадение с конечной точкой

Regex demo | Python demo


В вашем коде необязательно указывать группу необязательно, используя ? Шаблон для группы pic уже содержит совпадение с окончанием точка, чтобы вы могли пропустить end = r'\.$'

Между первым и вторым шаблоном есть один или несколько пробелов, которые вы можете сопоставить, используя [^\S\r\n]+, что будет совпадать 1 или более раз с любым символом пробела, кроме новой строки.


Например

import re
def get_pics(data, pic):
    base = r'(?P<level>\d{2})\s+(?P<name>\S+)'
    pattern = re.compile(f"^{base}[^\S\r\n]+{pic}$")
    for row in data.strip().split('\n'):
        re_match = pattern.match(row.strip())
        if not re_match:
            print(' => NOP:\n    ', row)
        else:
            match = re_match.groupdict()
            print('ok:', match)

data = """
   12 M-AR03-MONTANT-RDJ                 PIC S9(17).
   12 M-AR03-COMPTE-RDJ                  PIC X(8).
  09 M-N014-INC-CHARG-AMT-FSOL           PIC S9(9)V9(2) COMP-3.
  09 M-N014-CHARGE-TYPE-FSOL             PIC X(5).
"""

get_pics(data, r'\bPIC (?P<pic>(?:[A-Z]\d*\(\d+\))+)[^.\r\n]*\.')

Выход

ok: {'level': '12', 'name': 'M-AR03-MONTANT-RDJ', 'pic': 'S9(17)'}
ok: {'level': '12', 'name': 'M-AR03-COMPTE-RDJ', 'pic': 'X(8)'}
ok: {'level': '09', 'name': 'M-N014-INC-CHARG-AMT-FSOL', 'pic': 'S9(9)V9(2)'}
ok: {'level': '09', 'name': 'M-N014-CHARGE-TYPE-FSOL', 'pic': 'X(5)'}
1 голос
/ 16 февраля 2020

Я изменил ваш базовый шаблон для включения пробела в конце и создал другой шаблон для pic.

pat2 = r'(?P<level>\d{2})\s+(?P<name>\S+)\s+'
picpat = r'PIC\s(?P<pic>[^.\s]+)'

picpat соответствует чему-либо после 'PIC ', пока не достигнет точки или пробела ,

Regular expression visualization

Я немного изменил функцию, используя f-строку, чтобы объединить ее с шаблоном pi c , перебирая совпадения вместо строк.

def get_pics(data,pic):
    pat2 = r'(?P<level>\d{2})\s+(?P<name>\S+)\s+'
    pattern = f'{pat2}{pic}'
    #pattern = '{}{}'.format(pat2,pic)
    pattern = re.compile(pattern)
    for match in pattern.finditer(data):
        print(match.groupdict())


>>> get_pics(data,picpat)
{'level': '12', 'name': 'M-AR03-MONTANT-RDJ', 'pic': 'S9(17)'}
{'level': '12', 'name': 'M-AR03-COMPTE-RDJ', 'pic': 'X(8)'}
{'level': '09', 'name': 'M-N014-INC-CHARG-AMT-FSOL', 'pic': 'S9(9)V9(2)'}
{'level': '09', 'name': 'M-N014-CHARGE-TYPE-FSOL', 'pic': 'X(5)'}
>>> 
1 голос
/ 16 февраля 2020

Учитывая ваш ограниченный пример, я не могу понять, почему следующего недостаточно:

r'\sPIC\s((?:(?:[SV]\d|X))?\((?:\d+)\))+( COMP-3)?\.'

Нет необходимости, например, использовать \s+, если всегда есть только 1 пробел в качестве в вашем примере.

Точно так же нет причин не использовать литерал COMP-3 в регулярном выражении, если вы не сообщите нам, как может изменяться этот бит (например, Это COMP-, за которым следует целое число любого числа цифр ? Хорошо, хорошо, используйте COMP-\d+).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...