Pythonで、セミコロンで区切られた文字列を辞書に分割する


84

私は次のような文字列を持っています:

"Name1=Value1;Name2=Value2;Name3=Value3"

私がこれを行ったかのように、その文字列を受け取り、辞書を構築するPythonの組み込みクラス/関数はありますか?

dict = {
    "Name1": "Value1",
    "Name2": "Value2",
    "Name3": "Value3"
}

利用可能なモジュールを調べましたが、一致するものが見つからないようです。


おかげで、私は関連するコードを自分で作成する方法を知っていますが、そのような小さな解決策は通常、地雷原が起こるのを待っているので(つまり、誰かが次のように書いています:Name1 = 'Value1 = 2';)など。テストされた機能。

それなら自分でやります。


あなたの質問はs = r'Name1='Value=2';Name2=Value2;Name3=Value3;Name4="Va\"lue;\n3"'入力をサポートする必要がありますか(注:引用符で囲まれた文字列内のセミコロン、バックスラッシュを使用して引用符をエスケープし、\nエスケープを使用し、一重引用符と二重引用符の両方を使用します)?
jfs 2014

私のこの質問は6年以上前のものであり、これに関連するコードはかなり前から置き換えられています:)いいえ、引用符のサポートは必要ありませんでした。自分で何かを書くのではなく、ビルド済みの関数が欲しかっただけです。ただし、コードは長い間なくなっています。
Lasse V. Karlsen 2014

回答:


144

組み込みはありませんが、ジェネレーターの理解によってこれをかなり簡単に達成できます。

s= "Name1=Value1;Name2=Value2;Name3=Value3"
dict(item.split("=") for item in s.split(";"))

[編集] 更新から、引用を処理する必要があるかもしれないことを示します。これは、探している正確な形式(どの引用文字が受け入れられるか、どのエスケープ文字など)に応じて、事態を複雑にします。csvモジュールを調べて、自分の形式をカバーできるかどうかを確認することをお勧めします。次に例を示します:(CSVは一連のレコードを反復処理するように設計されているため、この例ではAPIが少し不格好であることに注意してください。したがって、最初の行だけを確認するために.next()を呼び出します。あなたのニーズに合う):

>>> s = "Name1='Value=2';Name2=Value2;Name3=Value3"

>>> dict(csv.reader([item], delimiter='=', quotechar="'").next() 
         for item in csv.reader([s], delimiter=';', quotechar="'").next())

{'Name2': 'Value2', 'Name3': 'Value3', 'Name1': 'Value1=2'}

ただし、フォーマットの正確な構造によっては、独自の単純なパーサーを作成する必要がある場合があります。


コードは引用符を処理しません。試してください:(s = "Name1='Value;2';Name2=Value2;Name3=Value3"注:引用符で囲まれたName1値のセミコロン)。
jfs 2014

1
2番目の例がなぜAttributeError: '_csv.reader' object has no attribute 'next'私に投げられるのか私にはわかりません。もちろんやりましたimport csv
ヨンジェ

@Brian値を文字列ではなく整数として格納する方法はありますか?
chasedByDeath

6

これはあなたが望んでいたことをすることに近づきます:

>>> import urlparse
>>> urlparse.parse_qs("Name1=Value1;Name2=Value2;Name3=Value3")
{'Name2': ['Value2'], 'Name3': ['Value3'], 'Name1': ['Value1']}

2
入力がある&場合%、または入力内にある場合は壊れます。
jfs 2014

@jfsですが、文字列にはこれらのいずれも含まれていません。
Vishal Singh

@VishalSingh:StackOverflowのほとんどの訪問者はグーグルから来ているので、ここでの回答は質問をした元の投稿者だけではありません。私はその後、私の文字列が含まれている場合があります「Pythonで辞書にセミコロンで区切られた文字列を、」解析する方法を探してここに来た場合&または%-少なくとも、答えは、このような文字列のために仕事をしないことを言及する価値があります。
jfs

3
s1 = "Name1=Value1;Name2=Value2;Name3=Value3"

dict(map(lambda x: x.split('='), s1.split(';')))

1

文字列結合とリスト内包表記で簡単に実行できます

",".join(["%s=%s" % x for x in d.items()])

>>d = {'a':1, 'b':2}
>>','.join(['%s=%s'%x for x in d.items()])
>>'a=1,b=2'

-2
easytiger $ cat test.out test.py | sed 's/^/    /'
p_easytiger_quoting:1.84563302994
{'Name2': 'Value2', 'Name3': 'Value3', 'Name1': 'Value1'}
p_brian:2.30507516861
{'Name2': 'Value2', 'Name3': "'Value3'", 'Name1': 'Value1'}
p_kyle:7.22536420822
{'Name2': ['Value2'], 'Name3': ["'Value3'"], 'Name1': ['Value1']}
import timeit
import urlparse

s = "Name1=Value1;Name2=Value2;Name3='Value3'"

def p_easytiger_quoting(s):
    d = {}
    s = s.replace("'", "")
    for x in s.split(';'):
        k, v = x.split('=')
        d[k] = v
    return d


def p_brian(s):
    return dict(item.split("=") for item in s.split(";"))

def p_kyle(s):
    return urlparse.parse_qs(s)



print "p_easytiger_quoting:" + str(timeit.timeit(lambda: p_easytiger_quoting(s)))
print p_easytiger_quoting(s)


print "p_brian:" + str(timeit.timeit(lambda: p_brian(s)))
print p_brian(s)

print "p_kyle:" + str(timeit.timeit(lambda: p_kyle(s)))
print p_kyle(s)

引用を処理しないため、これは質問に答えません。s = "Name1='Value1=2';Name2=Value2" and csv`を試してください(ブライアンの受け入れられた答えのように)またはparse_qs(カイルのように)それを正しくしますが、あなたはを上げますValueError。OPは特に、「このような小さなソリューションは、通常、地雷原が発生するのを待っている」と述べています。そのため、組み込みまたはその他の十分にテストされたソリューションが必要であり、コードを壊す例を示しています。
abarnert 2013年

ああ、私はそれを見ませんでした。それでも。反復が行われる前にメイン文字列内の関数を事前に解析し、置換関数を数千回呼び出すことは、すべてのソリューションよりも高速です。更新します
easytiger 2013年

どのようにそれを事前解析するのかわかりません。しかし、そうしても、これはOPが単純なソリューションで恐れていたものとまったく同じように見えます。先に他の鉱山はありませんか?OPの満足を証明できますか?
abarnert 2013年

さて、あなたの編集を見たので…まず、s.replace何もしません。無視した新しい文字列を返すだけです。第二に、あなたがそれを正しく理解したとしても(s = s.replace…)、それは問題を解決しません、それはそれの上に新しいものを追加するだけです。私の例またはOPのいずれかで試してみてください。
abarnert 2013年

仕様には、彼が質問で言及したサンプル入力の処理が明確に含まれていますName='Value1=2';。そして、あなたのコードはそれを処理しません。そして、私はあなただけのように遅いようになり、いくつかの方法でそれを解析することなく、そのサニタイズしたいかわからないurlparseか、csv最初の場所インチ
abarnert 2013年

-2

Value1、Value2が実際の値の単なるプレースホルダーである場合は、dict()関数をと組み合わせて使用することもできますeval()

>>> s= "Name1=1;Name2=2;Name3='string'"
>>> print eval('dict('+s.replace(';',',')+')')
{'Name2: 2, 'Name3': 'string', 'Name1': 1}

これは、dict()関数が構文を理解しているためdict(Name1=1, Name2=2,Name3='string')です。文字列内のスペース(各セミコロンの後など)は無視されます。ただし、文字列値には引用符が必要であることに注意してください。


おかげで、賛成のstring.replaceはうまくいきました。なぜ分割できなかったのかわからない。tcボックスでi = textcontrol.GetValue()を実行し、次にo = i.split( ';')を実行しましたが、replaceとは異なり、フォーマットについて不平を言っただけの文字列を出力しませんでした。
iancovici 2013年

1
s.replace(';';引用された値の中にある場合、ベースのソリューションは壊れます。evalは悪であり、この場合は不要です。
jfs 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.