Как написать грамматику для этого в pyparsing:сопоставьте набор слов, но не содержащий заданного шаблона

StackOverflow https://stackoverflow.com/questions/1805309

  •  05-07-2019
  •  | 
  •  

Вопрос

Я новичок в Python и pyparsing.Мне нужно выполнить следующее.

Мой пример строки текста выглядит следующим образом:

12 items - Ironing Service    11 Mar 2009 to 10 Apr 2009
Washing service (3 Shirt)  23 Mar 2009

Мне нужно извлечь описание товара, точка

tok_date_in_ddmmmyyyy = Combine(Word(nums,min=1,max=2)+ " " + Word(alphas, exact=3) + " " + Word(nums,exact=4))
tok_period = Combine((tok_date_in_ddmmmyyyy + " to " + tok_date_in_ddmmmyyyy)|tok_date_in_ddmmmyyyy)

tok_desc =  Word(alphanums+"-()") but stop before tok_period

Как это сделать?

Это было полезно?

Решение

Я бы посоветовал взглянуть на SkipTo как на класс pyparsing, который наиболее подходит, поскольку у вас есть хорошее определение текста нежелательных , но вы примете почти все до этого. Вот несколько способов использовать SkipTo:

text = """\
12 items - Ironing Service    11 Mar 2009 to 10 Apr 2009
Washing service (3 Shirt)  23 Mar 2009"""

# using tok_period as defined in the OP

# parse each line separately
for tx in text.splitlines():
    print SkipTo(tok_period).parseString(tx)[0]

# or have pyparsing search through the whole input string using searchString
for [[td,_]] in SkipTo(tok_period,include=True).searchString(text):
    print td

Оба цикла for выводят следующее:

12 items - Ironing Service    
Washing service (3 Shirt) 

Другие советы

М. К. Сараванан, эту конкретную проблему синтаксического анализа не так уж сложно решить с помощью good 'ole re:

import re
import string

text='''
12 items - Ironing Service    11 Mar 2009 to 10 Apr 2009
Washing service (3 Shirt)  23 Mar 2009
This line does not match
'''

date_pat=re.compile(
    r'(\d{1,2}\s+[a-zA-Z]{3}\s+\d{4}(?:\s+to\s+\d{1,2}\s+[a-zA-Z]{3}\s+\d{4})?)')
for line in text.splitlines():
    if line:
        try:
            description,period=map(string.strip,date_pat.split(line)[:2])
            print((description,period))
        except ValueError:
            # The line does not match
            pass

урожайность

# ('12 items - Ironing Service', '11 Mar 2009 to 10 Apr 2009')
# ('Washing service (3 Shirt)', '23 Mar 2009')

Главной рабочей лошадкой здесь, конечно же, является шаблон re.Давайте разберем это на части:

\d{1,2}\s+[a-zA-Z]{3}\s+\d{4} является ли регулярное выражение для даты эквивалентом tok_date_in_ddmmmyyyy. \d{1,2} соответствует одной или двум цифрам, \s+ соответствует одному или нескольким пробелам, [a-zA-Z]{3} соответствует 3 буквам и т.д.

(?:\s+to\s+\d{1,2}\s+[a-zA-Z]{3}\s+\d{4})? является регулярным выражением, окруженным (?:...).Это указывает на негруппирующееся регулярное выражение.Используя это, никакая группа (например,match.group(2)) присваивается этому регулярному выражению.Это важно, потому что date_pat.split() возвращает список, в котором каждая группа является членом списка.Подавляя группировку, мы сохраняем весь период 11 Mar 2009 to 10 Apr 2009 вместе.Вопросительный знак в конце указывает на то, что этот шаблон может встречаться ноль или один раз.Это позволяет регулярному выражению соответствовать обоим 23 Mar 2009 и 11 Mar 2009 to 10 Apr 2009.

text.splitlines() разбивает текст на \n.

date_pat.split('12 items - Ironing Service 11 Mar 2009 to 10 Apr 2009')

разбивает строку на регулярное выражение date_pat.Совпадение включено в возвращенный список.Таким образом, мы получаем:

['12 items - Ironing Service ', '11 Mar 2009 to 10 Apr 2009', '']

map(string.strip,date_pat.split(line)[:2]) улучшает результат.

Если line не соответствует date_pat, тогда date_pat.split(line) ВОЗВРАТ [line,], итак

description,period=map(string.strip,date_pat.split(line)[:2])

вызывает ValueError, потому что мы не можем распаковать список только с одним элементом в 2-кортеж.Мы перехватываем это исключение, но просто переходим к следующей строке.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top