2012-10-25 83 views
2

我有名字和年齡的文件,解析名稱與pyparsing

john 25 
bob 30 
john bob 35 

這裏是我迄今爲止

from pyparsing import * 

data = ''' 
    john 25 
    bob 30 
    john bob 35 
''' 

name = Word(alphas + Optional(' ') + alphas) 

rowData = Group(name + 
       Suppress(White(" ")) + 
       Word(nums)) 

table = ZeroOrMore(rowData) 

print table.parseString(data) 

我期待輸出

[['john', 25], ['bob', 30], ['john bob', 35]]

這裏是堆棧跟蹤

Traceback (most recent call last): 
    File "C:\Users\mccauley\Desktop\client.py", line 11, in <module> 
    eventType = Word(alphas + Optional(' ') + alphas) 
    File "C:\Python27\lib\site-packages\pyparsing.py", line 1657, in __init__ 
    self.name = _ustr(self) 
    File "C:\Python27\lib\site-packages\pyparsing.py", line 122, in _ustr 
    return str(obj) 
    File "C:\Python27\lib\site-packages\pyparsing.py", line 1743, in __str__ 
    self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig) 
    File "C:\Python27\lib\site-packages\pyparsing.py", line 1735, in charsAsStr 
    if len(s)>4: 
TypeError: object of type 'And' has no len() 
+0

我認爲你故意選擇'pyparsing'作爲學習練習嗎?使用內置的字符串函數甚至是正則表達式對於那些微不足道的東西更好 –

+0

@JonClements實際上這是一個很大的項目的一部分,我相信pyparsing比正則表達式更合適,我真的只需要知道如何做單一空間的事情。 – John

回答

3

pyparsing自動刪除空格,以便您可以編寫更清晰的語法。所以,你的名字解析器應該是更象:

# Parse for a name with an optional surname 
# Note that pyparsing is built to accept "john doe" or "john  doe" 
name = Word(alphas) + Optional(Word(alphas)) 

然後,該行解析器:對於每一行

# Parses a row of a name and an age 
row = Group(name) + Word(nums) 

你會得到一個相當複雜的結構,雖然([(['john', 'doe'], {}), '25'], {}),但我希望你能看到如何處理這個問題。我建議不要真正使用pyparsing來解析整個字符串,但是如果數據是基於行的,則會逐行地逐個解析它。使事情變得更簡單,我認爲:

for line in input_string.splitlines(): 
    results = row.parseString(line) 
    # Do something with results... 
+4

打印出來的結構看起來很複雜。實際上,結構是一個ParseResults,它可以像嵌套列表一樣迭代,或者如果有任何元素被賦予了結果名稱,則可以像dict一樣通過鍵來訪問。既然你有'Group'ed的主要名字(很好地完成了,btw),你甚至可以像'name,age = results'一樣進行元組解包。如果您將行更改爲'row = Group(name)('name')+ Word(nums)('age')',那麼您可以使用'results.age'或'results ['age' ]',當你在表達式中也有可選元素時,這非常有用。 – PaulMcG

+0

@PaulMcGuire另外,如果我沒有弄錯(糾正我,如果我錯了!),有'.scanString'來處理input_string.splitlines():行問題。也就是說,它會創建一個迭代器,以產生單個文法結果的輸出。因此,你可以用類似'for row.scanString():'中的結果來替換它。 – Hooked

+0

關閉 - 'scanString'返回一個生成器,爲每個找到的匹配生成一個'(tokens,start,end)'元組。 'searchString'只是'scanString','[令牌令牌,開始和結束於expr.scanString(s)]'的簡單封裝。 – PaulMcG

0

以下代碼可能會解決您使用內置字符串庫的問題。

def main(): 
    f = open('filename.txt') 
    fe = open('ERROR.TXT','w+') 
    for line in f.readlines(): 
     # print line, 
     lst = line.split() 
     try: 
      name = lst[0] 
      age = lst[1] 

     # process name and age valuse 

     except IndexError as e: 
      print e 
      fe.write(e) 
     except IOError as e: 
      print e 
      fe.write(e) 

if __name__ == '__main__': 
    main() 
+0

我希望。請看我對這個問題的評論。 – John