2012-04-16 68 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)} 

虽然我认为这是推动可读性的边界。