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番目:そのようなフォーマットも検討したい:

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

最善の方法は何ですか?

4

2 に答える 2

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」はカード名の一部として扱われます。

  • 正規表現に慣れていない場合は、次のように読みます。0 個以上の数字に一致する一致グループを形成します。この後に、0 個以上の空白文字が続きます。これには別のグループが続きますが、この次のグループにはフラグが付けられている(?:だけでなく、(グループであるが出力で一致グループを作成しません。このグループは、'x' または 'X' の後に 1 つ以上の空白文字が続く文字クラスです。1 つの非空白文字で始まり、0 個以上の任意の文字が続く、別の一致グループを形成します。

  • 同じ名前のカードをすべて合計したいと思いますか? そのための最善の方法は、defaultdict()ここで示したように使用することです。

  • 正当なカード名が「x」または「X」で始まらない場合は、パターンを変更して、カード名とカード名の間にスペースがなくても「x」を保持しないようにすることができます。これを行うには、「x」に一致するパターンを this:(?:[xX]\s+)? からthis: に変更します (シングルが の後にシングルに変更されたため、ゼロの空白文字が受け入れられることに(?:[xX]\s*)? 注意してください)。+*\s

于 2012-04-16T23:35:34.163 に答える
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()notの辞書を返すため、目的を達成するために使用することはできませsubgroup_name: matchmatch: match。代わりに、一致を実行してからグループを取得します。これにより、一致したタプルが得られます。

エクストラ in で表記をサポートするの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)}

これは読みやすさの限界を押し広げていると私は主張しますが。

于 2012-04-16T22:49:18.263 に答える