2010-07-01 161 views
1

我必須解析python中的輸入字符串並從中提取某些部分。在python中提取部分字符串

字符串的格式是

(xx,yyy,(aa,bb,...)) // Inner parenthesis can hold one or more characters in it 

我想要一個函數返回XX,YYYY和含AA,BB列表...等

我可以ofcourse試圖分裂做括號之類的東西,但我想知道是否有從一個字符串中提取這種信息的適當Python的方式

我有這樣的代碼工作,但有沒有更好的方式來做到這一點(沒有正則表達式)

def processInput(inputStr): 
    value = inputStr.strip()[1:-1] 
    parts = value.split(',', 2) 
    return parts[0], parts[1], (parts[2].strip()[1:-1]).split(',') 
+1

如果內在價值被引用,你可以實際上只是'的eval()',雖然我肯定不會推薦它:) – 2010-07-01 02:33:16

+0

http://gskinner.com/RegExr/ – 2010-07-01 03:35:53

回答

3

如果你到RE過敏,你可以使用pyparsing

>>> import pyparsing as p 
>>> ope, clo, com = map(p.Suppress, '(),') 
>>> w = p.Word(p.alphas) 
>>> s = ope + w + com + w + com + ope + p.delimitedList(w) + clo + clo 
>>> x = '(xx,yyy,(aa,bb,cc))' 
>>> list(s.parseString(x)) 
['xx', 'yyy', 'aa', 'bb', 'cc'] 

pyparsing也使得如果需要,可以輕鬆控制結果的確切形式(例如,將最後3個項目分組到自己的子列表中)。但我認爲最好的方面是如何自然(取決於你想要投入多少空間),你可以閱讀「語法規範」:一個開放的paren,一個單詞,一個逗號,一個單詞,一個逗號,一個open paren,單詞分隔列表,兩個封閉的圓括號(如果您發現上面s的任務不容易閱讀,我想這是我的錯,因爲不選擇更長的標識符;-)。

+0

亞歷克斯,你銀色的魔鬼!我想我們可能會在一分鐘內發佈! – PaulMcG 2010-07-01 05:22:20

+0

@保羅,是的 - 當我開始寫我的時候,你的帖子不在那裏,我敢肯定,反過來也是一樣,所以我們一定在同一時間寫了很多東西! – 2010-07-01 05:29:54

2

讓我們使用正則表達式!

/\(([^,]+),([^,]+),\(([^)]+)\)\)/ 

對陣,首先捕獲組含有XX,第二個包含YYY,分割第三對,,你有你的清單。

+0

完全無關。它讓我想起了這個XKCD:http://xkcd.com/208/ – Caladain 2010-07-01 02:34:51

+0

使用正則表達式肯定是一種好方法,是否有創建一個表達式,如sortof reverse printf並使用它來提取所需的部分? – randomThought 2010-07-01 02:35:41

+0

在C中有一個'sscanf'函數,但我不知道Python在標準庫中是否有等價物。也許有人在第三方庫中實現了它。 – 2010-07-01 02:40:08

1

我不知道這是更好的,但它是一個不同的方式來做到這一點。使用先前建議的正則表達式

def processInput(inputStr): 
     value = [re.sub('\(*\)*','',i) for i in inputStr.split(',')] 
     return value[0], value[1], value[2:] 

或者,您可以使用兩個鏈接替換函數來代替正則表達式。

2

這樣怎麼樣?

>>> import ast 
>>> import re 
>>> 
>>> s="(xx,yyy,(aa,bb,ccc))" 
>>> x=re.sub("(\w+)",'"\\1"',s) 
# '("xx","yyy",("aa","bb","ccc"))' 
>>> ast.literal_eval(x) 
('xx', 'yyy', ('aa', 'bb', 'ccc')) 
>>> 
3

如果你的括號嵌套可以有任意的深度,然後使用regexen不會做,你需要一個狀態機或解析器。 Pyparsing支持遞歸語法使用前瞻性聲明class轉發:

from pyparsing import * 

LPAR,RPAR,COMMA = map(Suppress,"(),") 
nestedParens = Forward() 
listword = Word(alphas) | '...' 
nestedParens << Group(LPAR + delimitedList(listword | nestedParens) + RPAR) 

text = "(xx,yyy,(aa,bb,...))" 
results = nestedParens.parseString(text).asList() 
print results 

text = "(xx,yyy,(aa,bb,(dd,ee),ff,...))" 
results = nestedParens.parseString(text).asList() 
print results 

打印:

[['xx', 'yyy', ['aa', 'bb', '...']]] 
[['xx', 'yyy', ['aa', 'bb', ['dd', 'ee'], 'ff', '...']]] 
+0

+1,因爲它展示了'pyparsing'幾個更高級的特性,同時我堅持了非常基礎;-) – 2010-07-01 05:31:35

0

您的解決方案體面(簡單,高效)。如果您不信任數據源,則可以使用正則表達式來限制語法。

import re 
parser_re = re.compile(r'\(([^,)]+),([^,)]+),\(([^)]+)\)') 
def parse(input): 
    m = parser_re.match(input) 
    if m: 
     first = m.group(1) 
     second = m.group(2) 
     rest = m.group(3).split(",") 
     return (first, second, rest) 
    else: 
     return None 

print parse('(xx,yy,(aa,bb,cc,dd))') 
print parse('xx,yy,(aa,bb,cc,dd)') # doesn't parse, returns None 

# can use this to unpack the various parts. 
# first,second,rest = parse(...) 

打印:

('xx', 'yy', ['aa', 'bb', 'cc', 'dd']) 
None