2012-04-16 69 views
1

我需要處理的文本來創建一個字典文字的{name: quantity}使用groupdict解析字符串與dict

變種:

2 Cardname 
3 Cardname Two 
1 Cardname Three 

Cardname 
Cardname Two 
Cardname Three 

所以我寫了一個基本的代碼:

card_list = card_area.splitlines() 
card_dict = {} 

for card in card_list: 
    qty_re = re.search('^\d{1,6}', card) 
     if qty_re: 
      qty = qty_re.group() 
     else: 
      qty = 1 

    name_re = re.search('[A-Za-z ]+$', card) 
     if name_re: 
      name = name_re.group() 
     else: 
      name = None 

    if name: 
     card_dict[name] = qty 

第一個問題:如果字符串的某些元素不存在(不是數量或空字符串),我可以使用groupdict method

二:我也想考慮這樣的格式:

2 x Cardname 
3x Cardname Two 
1 xCardname Three 
1xCardname Four 

什麼是最好的方法是什麼?

+0

我完全忘記了'splitlines' :) – 2012-04-16 22:35:57

回答

1

解決方案。請注意遵循。

from collections import defaultdict 
import re 

# card_list = card_area.splitlines() 
card_list = [ 
    "2 Cardname", "3 Cardname Two", "1 Cardname Three", 
    "Cardname", "Cardname Two", "Cardname Three", 
    "1x Cardname", "4X Cardname Two", "2 X Cardname Three", 
] 

card_dict = defaultdict(int) 

pat = re.compile(r'(\d*)\s*(?:[xX]\s+)?(\S.*)') 

for card in card_list: 
    m = re.search(pat, card) 
    if not m: 
     continue 
    if m.group(1): 
     qty = int(m.group(1)) 
    else: 
     qty = 1 

    name = m.group(2) 
    card_dict[name] += qty 


if not card_dict: 
    print("empty card_dict!") 
else: 
    for name in sorted(card_dict): 
     print("%20s|%4d" % (name, card_dict[name])) 

注:

  • 我建議預編譯正則表達式模式,對於速度。

  • 處理此問題的最佳方法是抓取計數和卡的單個正則表達式模式。我添加了一個可選模式,用可選的'x'識別卡片格式。使用一個字符類,我使它匹配大寫或小寫'x'。數字和'x'之間的空格是可選的,但'x'和卡片名稱之間必須有空格,否則'x'將被視爲卡片名稱的一部分。

  • 如果您不熟悉正則表達式,請閱讀以下方法:形成匹配零個或多個數字的匹配組。隨後是零個或多個空白字符。接下來是另一個組,但此後面的組標記爲(?:而不僅僅是(,因此它是一個組,但不會在輸出中生成匹配組;該組是一個匹配'x'或'X'的字符類,後跟一個或多個空格字符。形成另一個匹配組,它以一個非空白字符開頭,後面跟零個或多個任意字符。

  • 我相信你想總結同名的所有名片?最好的方法是使用defaultdict(),正如我在這裏所示。

  • 如果沒有任何合法卡片名稱以'x'或'X'開頭,即使卡片名稱與卡片名稱之間沒有空格,也可以更改圖案以不保留'x'。要做到這一點,換着花樣來匹配「X」從這個:(?:[xX]\s+)?這樣:(?:[xX]\s*)?(請注意,一個+改爲單*\s後,所以零個空白字符現在被接受。)

1

你可以用一個正則表達式做到這一點:

import re 

regex = re.compile(r'(\d*)([A-Za-z ]+)$') 
card_list = ["2 Cardname", "3 Cardname Two", "Cardname Three"] 
card_dict = {} 

for quantity, name in (regex.match(card).groups() for card in card_list): 
    if not quantity: 
     quantity = 1 
    card_dict[name.strip()] = int(quantity) 

print(card_dict) 

給予我們:

{'Cardname Two': 3, 'Cardname Three': 1, 'Cardname': 2} 

不能使用groupdict()達到你想要的東西,因爲它返回的subgroup_name: matchmatch: match的字典。 。相反,我們做一個匹配,然後拿到團體,這讓我們在與我們的比賽的元組

一個額外的x中很容易支持的符號,我們只是將其添加到正則表達式:

regex = re.compile(r'(\d*)x?([A-Za-z ]+)$') 

通過匹配x?,我們匹配x,如果它存在,則不匹配。這裏唯一的潛在問題是如果你有一個以x開頭的卡片名稱。

需要注意的是,如果你可以假設,這一數目將永遠在那裏,你可以做到這一點作爲一個班輪:

{name.strip(): quantity for quantity, name in (regex.match(card).groups() for card in card_list)} 

雖然我認爲這是推動可讀性的邊界。