簡體   English   中英

使用 Pyparsing 查找字符串中的元素列表

[英]Finding lists of elements within a string using Pyparsing

我正在嘗試使用 Pyparsing 解決以下問題:我想在字符串中搜索三種元素的出現:

  1. 小寫單詞
  2. 文字字符串“OBJ”后面的小寫單詞
  3. 包含這些元素之一的列表,用“,”分隔

示例字符串可以是“foo bar OBJ baz foo,bar

我想在自己的解析操作中處理這些元素中的每一個。

這是我的代碼:

import pyparsing
from pyparsing import Word, Literal, alphas

def found_word(s, l, t):
    print('word')
def found_obj(s, l, t):
    print('obj')
def found_list(s, l, t):
    print('list')

def process(string):

    word = ~Literal('OBJ ') + Word(alphas.lower())
    word.setParseAction(lambda s,l,t: found_word(s, l, t))
    obj = Literal('OBJ ') +  Word(alphas.lower())
    obj.setParseAction(lambda s,l,t: found_obj(s, l, t))
    item = word | obj
    list = pyparsing.delimitedList(item, delim=',')
    list.setParseAction(lambda s,l,t: found_list(s, l, t))
    element = word | obj | list

    parser = pyparsing.OneOrMore(element)
    parser.searchString(string).pprint()

if __name__ == "__main__":
    process('foo bar OBJ baz foo,bar')

編輯:我在 parseActions 中進行了一些測試 output 只是為了查看它們是否被調用。 所需的 output 將是:

word
word
obj
word
word
list

實際的 output 是:

word
word
obj
word
word

即不調用列表的 parseAction。 為了實現這一點,我需要如何更改我的代碼?

更新delimitedList 沒有按我的預期工作。 當我打電話時

pyparsing.OneOrMore(list).searchString('foo,bar baz')

found_list似乎被調用了兩次,盡管我的字符串中只有一個列表元素:

word
word
list
word
list

嘗試這個:

s = 'foo bar OBJ baz foo,bar'


for w in s.split(' '):
  if w.islower():
    print("word")
  if 'OBJ' in w:
    print("obj")
  if ',' in w:
    print('list')

您的list沒有被解析的原因在於這個表達式:

element = word | obj | list

因為您正在檢查list之前的word (在 Python 中工作時,這是一個非常糟糕的變量名,順便說一句),所以“foo,bar”中的前導“foo”被作為一個word處理,因為 '|' 是一個急切的運算符,匹配第一個匹配表達式。

您可以通過更改element中表達式的順序來解決此問題:

element = list | word | obj

或者使用 '^' 而不是 '|'。 '^' 是一個耐心的運算符 - 它評估所有替代表達式並選擇最長的匹配項。

element = word ^ obj ^ list

通過這些更改中的任何一個,您的 output 現在變為:

word
list
word
list
obj
word
word
list

為什么所有列表都匹配? 因為delimitedList將匹配單個項目:

>>> wd = Word(alphas)
>>> wdlist = delimitedList(wd)
>>> print(wdlist.parseString('xyz'))
['xyz']

如果要強制列表必須具有 > 1 項,則可以添加條件解析操作:

>>> wdlist.addCondition(lambda t: len(t)>1)
>>> print(wdlist.parseString('xyz')) 
... raises exception ...

此外,delimitedLists 不會自動對它們的結果進行分組:

>>> print((wd + wdlist).parseString('xyz abc,def'))
['xyz', 'abc', 'def']

如果要將列表內容作為列表保留在結果中,則將列表表達式包裝在一個組中:

>>> print((wd + Group(wdlist)).parseString('xyz abc,def'))
['xyz', ['abc', 'def']]

這是我的process()方法的更新版本:

def process(string):
    print(string)

    word = ~Literal('OBJ') + Word(alphas.lower())
    word.addParseAction(lambda s,l,t: found_word(s, l, t))
    word.setName("word")
    obj = Literal('OBJ') +  Word(alphas.lower())
    obj.setName("obj")
    obj.addParseAction(lambda s,l,t: found_obj(s, l, t))
    item = word | obj
    list = Group(pyparsing.delimitedList(item, delim=',')
                    .addCondition(lambda t: len(t)>1))
    list.setName("list")
    list.addParseAction(lambda s,l,t: found_list(s, l, t))
    element = obj | list | word

    parser = pyparsing.OneOrMore(element)
    parser.searchString(string).pprint()

這給出了這個 output:

foo bar OBJ baz foo,bar
word
word
word
word
obj
word
word
list
[['foo', 'bar', 'OBJ', 'baz', ['foo', 'bar']]]

您會注意到我為您的每個表達式添加了setName()調用。 這樣我就可以添加setDebug()來獲取 pyparsing 的調試 output。 通過添加:

word.setDebug()
obj.setDebug()
list.setDebug()

在調用parseString之前,你會得到這個調試 output。 它可能有助於解釋為什么您在示例 output 中獲得了重復的“單詞”。

foo bar OBJ baz foo,bar
Match obj at loc 0(1,1)
Exception raised:Expected "OBJ", found 'f'  (at char 0), (line:1, col:1)
Match list at loc 0(1,1)
Match word at loc 0(1,1)
word
Matched word -> ['foo']
Exception raised:failed user-defined condition, found 'f'  (at char 0), (line:1, col:1)
Match word at loc 0(1,1)
word
Matched word -> ['foo']
Match obj at loc 3(1,4)
Exception raised:Expected "OBJ", found 'b'  (at char 4), (line:1, col:5)
Match list at loc 3(1,4)
Match word at loc 4(1,5)
word
Matched word -> ['bar']
Exception raised:failed user-defined condition, found 'b'  (at char 4), (line:1, col:5)
Match word at loc 3(1,4)
word
Matched word -> ['bar']
Match obj at loc 7(1,8)
obj
Matched obj -> ['OBJ', 'baz']
Match obj at loc 15(1,16)
Exception raised:Expected "OBJ", found 'f'  (at char 16), (line:1, col:17)
Match list at loc 15(1,16)
Match word at loc 16(1,17)
word
Matched word -> ['foo']
Match word at loc 20(1,21)
word
Matched word -> ['bar']
list
Matched list -> [['foo', 'bar']]
Match obj at loc 23(1,24)
Exception raised:Expected "OBJ", found end of text  (at char 23), (line:1, col:24)
Match list at loc 23(1,24)
Match word at loc 23(1,24)
Exception raised:Expected W:(abcd...), found end of text  (at char 23), (line:1, col:24)
Match obj at loc 23(1,24)
Exception raised:Expected "OBJ", found end of text  (at char 23), (line:1, col:24)
Exception raised:Expected {word | obj}, found end of text  (at char 23), (line:1, col:24)
Match word at loc 23(1,24)
Exception raised:Expected W:(abcd...), found end of text  (at char 23), (line:1, col:24)
Match obj at loc 23(1,24)
Exception raised:Expected "OBJ", found end of text  (at char 23), (line:1, col:24)
Match list at loc 23(1,24)
Match word at loc 23(1,24)
Exception raised:Expected W:(abcd...), found end of text  (at char 23), (line:1, col:24)
Match obj at loc 23(1,24)
Exception raised:Expected "OBJ", found end of text  (at char 23), (line:1, col:24)
Exception raised:Expected {word | obj}, found end of text  (at char 23), (line:1, col:24)
Match word at loc 23(1,24)
Exception raised:Expected W:(abcd...), found end of text  (at char 23), (line:1, col:24)
[['foo', 'bar', 'OBJ', 'baz', ['foo', 'bar']]]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM