使用groupdict将字符串解析为dict

时间:2012-04-16 22:30:56

标签: python regex

我需要处理文本以创建字典{name: quantity}

文字变体:

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

最好的方法是什么?

2 个答案:

答案 0 :(得分: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: match而不是match: 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)}

虽然我认为这会推动可读性的界限。

答案 1 :(得分: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'将被视为卡名称的一部分。

    < / LI>
  • 如果您不熟悉正则表达式,请按以下步骤阅读:正确形成匹配零个或多个数字的匹配组。接下来是零个或多个空格字符。接下来是另一个组,但是此后续组标记为(?:而不仅仅是(,因此它是一个组,但不会在输出中创建匹配组;该组是一个匹配“x”或“X”的字符类,后跟一个或多个空格字符。形成另一个匹配组,该组以一个非空白字符开头,后跟零个或多个任何字符。

  • 我相信你想要把所有同名的牌都加起来?最好的方法是使用我在此处显示的defaultdict()

  • 如果没有合法的卡片名称以“x”或“X”开头,即使它与卡片名称之间没有空格,您也可以将模式更改为不保留“x”。要做到这一点,请更改模式以匹配以下内容中的“x”:(?:[xX]\s+)?至:(?:[xX]\s*)?(请注意,单个+更改为单个*之后\s,现在接受零空格字符。)