Необязательное совпадение с регулярным выражением в Python не удается - PullRequest
2 голосов
/ 03 мая 2010
tickettypepat = (r'MIS Notes:.*(//p//)?.*')
retype = re.search(tickettypepat,line)
if retype:
  print retype.group(0)
  print retype.group(1)

С учетом ввода.

MIS Notes: //p//

Может кто-нибудь сказать мне, почему группа (0)

MIS Notes: //p// 

и группа (1) возвращается как None?

Первоначально я использовал регулярное выражение, потому что до того, как я столкнулся с проблемами, сопоставление было более сложным, чем просто сопоставление // p // вот полный код. Я довольно новичок в этом, так что простите мою нубизм, я уверен, что есть лучшие способы сделать большую часть этого, и если кто-то захочет указать те, которые будут удивительными Но помимо проблемы с регулярным выражением для // [pewPEW] //, который слишком жаден, он кажется функциональным. Я ценю помощь.


Принимает текст и очищает / конвертирует некоторые вещи.

filename = (r'.\4-12_4-26.txt')
import re
import sys
#Clean up output from the web to ensure that you have one catagory per line
f = open(filename)
w = open('cleantext.txt','w')

origdatepat = (r'(Ticket Date: )([0-9]+/[0-9]+/[0-9]+),( [0-9]+:[0-9]+ [PA]M)')
tickettypepat = (r'MIS Notes:.*(//[pewPEW]//)?.*')

print 'Begining Blank Line Removal'
for line in f:
    redate = re.search(origdatepat,line)
    retype = re.search(tickettypepat,line)
    if line == ' \n':
        line = ''
        print 'Removing blank Line'
#remove ',' from time and date line    
    elif redate:
        line = redate.group(1) + redate.group(2)+ redate.group(3)+'\n'
        print 'Redating... ' + line

    elif retype:
        print retype.group(0)
        print retype.group(1)

        if retype.group(1) == '//p//':
            line = line + 'Type: Phone\n'
            print 'Setting type for... ' + line
        elif retype.group(1) == '//e//':
            line = line + 'Type: Email\n'
            print 'Setting type for... ' + line
        elif retype.group(1) == '//w//':
            line = line + 'Type: Walk-in\n'
            print 'Setting type for... ' + line
        elif retype.group(1) == ('' or None):
            line = line + 'Type: Ticket\n'
            print 'Setting type for... ' + line

    w.write(line)

print 'Closing Files'                 
f.close()
w.close()

А вот несколько примеров ввода.

Ticket No.: 20100426132 
Ticket Date: 04/26/10, 10:22 AM 
Close Date:  
Primary User: XXX
Branch: XXX
Help Tech: XXX
Status: Pending  
Priority: Medium  
Application: xxx
Description: some issue
Resolution: some resolution
MIS Notes: some random stuff //p// followed by more stuff
Key Words:  

Ticket No.: 20100426132 
Ticket Date: 04/26/10, 10:22 AM 
Close Date:  
Primary User: XXX
Branch: XXX
Help Tech: XXX
Status: Pending  
Priority: Medium  
Application: xxx
Description: some issue
Resolution: some resolution
MIS Notes: //p//
Key Words:  

Ticket No.: 20100426132 
Ticket Date: 04/26/10, 10:22 AM 
Close Date:  
Primary User: XXX
Branch: XXX
Help Tech: XXX
Status: Pending  
Priority: Medium  
Application: xxx
Description: some issue
Resolution: some resolution
MIS Notes: //e// stuff....
Key Words:  


Ticket No.: 20100426132 
Ticket Date: 04/26/10, 10:22 AM 
Close Date:  
Primary User: XXX
Branch: XXX
Help Tech: XXX
Status: Pending  
Priority: Medium  
Application: xxx
Description: some issue
Resolution: some resolution
MIS Notes:
Key Words:  

Ответы [ 3 ]

4 голосов
/ 03 мая 2010

MIS Notes:.*(//p//)?.* работает следующим образом, на примере "MIS Notes: //p//" в качестве цели:

  1. MIS Notes: соответствует "MIS Notes:", здесь никаких сюрпризов.
  2. .* сразу доходит до конца строки (пока соответствует "MIS Notes: //p//")
  3. (//p//)? необязательно. Ничего не происходит.
  4. .* не осталось ничего, чтобы соответствовать, мы уже в конце строки. Поскольку звезда допускает нулевые совпадения для предыдущего атома, механизм регулярных выражений перестает сообщать всю строку как совпадение, а подгруппа - как пустую.

Теперь, когда вы изменяете регулярное выражение на MIS Notes:.*(//p//).*, поведение меняется:

  1. MIS Notes: соответствует "MIS Notes:", здесь все еще нет сюрпризов.
  2. .* сразу доходит до конца строки (пока соответствует "MIS Notes: //p//")
  3. (//p//) необходимо. Двигатель начинает возвращать символ за символом, чтобы выполнить это требование. (Совпадение пока что "MIS Notes: ")
  4. (//p//) может совпадать. Подгруппа 1 сохранена и содержит "//p//".
  5. .* до конца строки. Подсказка: если вас не интересует то, что совпадает, это лишнее и вы можете удалить его.

Теперь, когда вы измените регулярное выражение на MIS Notes:.*?//(p)//, поведение снова изменится:

  1. MIS Notes: соответствует "MIS Notes:", и все же здесь нет сюрпризов.
  2. .*? не является жадным и проверяет следующий атом перед тем, как продолжить (пока соответствует "MIS Notes: ")
  3. //(p)// может совпадать. Первая подгруппа сохранена и содержит "p".
  4. Готово. Обратите внимание, что отслеживание не происходит, это экономит время.

Теперь, если вы знаете, что до //p// не может быть /, вы можете использовать: MIS Notes:[^/]*//(p)//:

  1. MIS Notes: соответствует "MIS Notes:", вы поняли.
  2. [^/]* может перемотать вперед до первого слэша (это быстрее, чем .*?)
  3. //(p)// может совпадать. Подгруппа одна сохранена и содержит "p".
  4. Готово. Обратите внимание, что отслеживание не происходит, это экономит время. Это должно быть быстрее, чем версия # 3.
1 голос
/ 03 мая 2010

Regex являются жадными, что означает, что .* соответствует как можно большей строке. Таким образом, для дополнительной группы не осталось ничего подходящего. group(0) - это всегда полное совпадение укуса.

От вашего комментария, почему вы хотите регулярное выражение? Разве этого не достаточно?

if line.startswith('MIS Notes:'): # starts with that string
    data = line[len('MIS Notes:'):] # the rest in the interesting part
    if '//p//' in data:
        stuff, sep, rest = data.partition('//p//') # or sothing like that
    else:
        pass #other stuff
0 голосов
/ 03 мая 2010

Шаблон неоднозначен для ваших целей. Было бы хорошо сгруппировать их по префиксу или суффиксу. В приведенном здесь примере я выбрал группировку префиксов. По сути, если в строке встречается //p//, то префикс не пустой. Суффикс будет все после элемента //p// или все в строке, если он не существует

import re
lines = ['MIS Notes: //p//',
    'MIS Notes: prefix//p//suffix']

tickettypepat = (r'MIS Notes: (?:(.*)//p//)?(.*)')
for line in lines:
    m = re.search(tickettypepat,line)
    print 'line:', line
    if m: print 'groups:', m.groups()
    else: print 'groups:', m

Результаты:

line: MIS Notes: //p//
groups: ('', '')
line: MIS Notes: prefix//p//suffix
groups: ('prefix', 'suffix')
...