2012-09-17 61 views
1

就拿從IANA格式爲:http://www.iana.org/assignments/language-subtag-registry級聯字符串分割,Python的方式

%% 
Type: language 
Subtag: aa 
Description: Afar 
Added: 2005-10-16 
%% 
Type: language 
Subtag: ab 
Description: Abkhazian 
Added: 2005-10-16 
Suppress-Script: Cyrl 
%% 
Type: language 
Subtag: ae 
Description: Avestan 
Added: 2005-10-16 
%% 

說我打開文件:

import urllib 
f = urllib.urlopen("http://www.iana.org/assignments/language-subtag-registry") 
all=f.read() 

通常你會做這樣的

lan=all.split("%%") 

iterate lan和split("\n")然後迭代結果和split(「:」),有沒有辦法到python在一批沒有迭代和輸出仍然是這樣的: [[["Type","language"],["Subtag", "ae"],...]...]

回答

3

作爲一個單一的理解:

raw = """\ 
%% 
Type: language 
Subtag: aa 
Description: Afar 
Added: 2005-10-16 
%% 
Type: language 
Subtag: ab 
Description: Abkhazian 
Added: 2005-10-16 
Suppress-Script: Cyrl 
%% 
Type: language 
Subtag: ae 
Description: Avestan 
Added: 2005-10-16 
%%""" 


data = [ 
    dict(
     row.split(': ') 
     for row in item_str.split("\n") 
     if row # required to avoid the empty lines which contained '%%' 
    ) 
    for item_str in raw.split("%%") 
    if item_str # required to avoid the empty items at the start and end 
] 
>>> data[0]['Added'] 
'2005-10-16' 
+0

這是我正在尋找的答案+ 1/accept –

+0

@EduardFlorinescu:剛注意到這個問題已經過了一年了。噢 - 很高興幫助 – Eric

3

如果您在每次拆分之後獲得的元素在語義上不同,我認爲在一次嘗試執行此操作時沒有任何意義。

你可以先用「:」分開 - 那會讓你得到細粒度的數據 - 但是如果你不知道這些數據是屬於什麼的話,那會有什麼好處呢?

這就是說,你可以把分離的所有級別發電機內,而且它產生 字典對象與您的數據,準備consunption:

def iana_parse(data): 
    for record in data.split("%%\n"): 
     # skip empty records at file endings: 
     if not record.strip(): 
      continue 
     rec_data = {} 
     for line in record.split("\n"): 
      key, value = line.split(":") 
      rec_data[key.strip()] = value.strip() 
     yield rec_data 

這是可以做到的一個襯墊正如你在評論中所要求的那樣 - 但是正如我之前所說的那樣, 它可以寫成適合單行表達式。寫出比上面的例子花費更多時間,幾乎不可能維護。上面例子中的代碼展示了幾行代碼中的邏輯,這些代碼被置於「不擋路」的位置 - 即不是以實際數據進行內聯的內聯,從而爲這兩項任務提供可讀性和可維護性。

這就是說,只要你想,可以這樣做解析爲嵌套列表的結構:

structure = [[[token.strip() for token in line.split(":")] for line in record.split("\n") ] for record in data.split("%%") if record.strip() ] 
+0

所以不更多鈔票來得到它這樣'[[[ 「類型」, 「語言」],[ 「子標記」, 「AE」 ],...] ...]'沒有迭代它? –

+0

@EduardFlorinescu不是真的,除此之外,如果你調用一個函數來爲你生成這個輸出,它會在內部進行迭代,迭代有什麼不好? – ted

+1

它可以寫成適合一行中的單個表達式。它比上面的例子需要更多的時間來寫,並且幾乎不可能保持。上面例子中的代碼展示了幾行代碼中的邏輯,這些代碼放置在「離開」的位置 - 即不是內聯的實際數據,這爲兩個任務提供了可讀性和可維護性。 – jsbueno

2

Regexes,但我不明白這一點:

re.split('%%|:|\\n', string) 

這裏多模式被鏈接使用或|運營商。

+0

對於「我看不到點」的+1 :-) – jsbueno

+0

但是,然後你不知道何時一個記錄結束,下一個開始,除非例如,您需要硬編碼每條記錄都必須以「類型」字段開頭的要求。你也不可能在字段值中使用分隔符,在這種情況下這可能不是一個嚴重的問題(並且/或者如果你願意的話,你可以在'%%'的兩邊都要求換行符)。 – tripleee

+0

@tripleee:如何用先行模式分割?我可以對分隔符進行相同操作(它們必須被轉義或者您認爲只有第一個分隔符)。如果你有興趣,我可以給你看一些這樣的正則表達式,但是你也可以回頭看看awnser中鏈接的正則表達式文檔。此外,這只是用戶所要求的一個問題,我認爲這種方法非常適用於解析目的。即使對於csv文件,我認爲逐個使用這些字段也是明智之舉,這使得檢測轉義的分隔符變得更容易。 (我知道有'csv'模塊) – ted

2

您可以使用itertools.groupby

ss = """%% 
Type: language 
Subtag: aa 
Description: Afar 
Added: 2005-10-16 
%% 
Type: language 
Subtag: ab 
Description: Abkhazian 
Added: 2005-10-16 
Suppress-Script: Cyrl 
%% 
Type: language 
Subtag: ae 
Description: Avestan 
Added: 2005-10-16 
""" 
sss = ss.splitlines(True) #List which looks like you're iterating over a file object 


import itertools 

output = [] 
for k,v in itertools.groupby(sss,lambda x: x.strip() == '%%'): 
    if(k): #Hit a '%%' record. Need a new group. 
     print "\nNew group:\n" 
     current = {} 
     output.append(current) 
    else: #just a regular record, write the data to our current record dict. 
     for line in v: 
      print line.strip() 
      key,value = line.split(None,1) 
      current[key] = value 

一個這個答案的好處是,它不需要您閱讀整個文件。整個表達式被懶惰地評估。