2

我需要处理文本以创建字典{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 方法吗?

第二:我也想考虑这样的格式:

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

什么是最好的方法 ?

4

2 回答 2

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: matchnot的字典match: match。相反,我们进行匹配,然后获取组,这为我们提供了一个包含匹配项的元组。

用额外x的 in 支持符号非常容易,我们只需将其添加到正则表达式中:

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)}

尽管我认为这是在推动可读性的界限。

于 2012-04-16T22:49:18.263 回答
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' 从 this:(?:[xX]\s+)? 到 this: (请注意,在之后(?:[xX]\s*)? 单个+更改为单个,因此现在将接受零个空白字符。)*\s

于 2012-04-16T23:35:34.163 回答