Разделение строки, разделенной точкой с запятой, в словарь в Python


86

У меня есть строка, которая выглядит так:

"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используется escape, используются как одинарные, так и двойные кавычки)?
jfs

Этому моему вопросу более 6 лет, код, который его затрагивал, давно заменен :) И нет, он не требовал поддержки кавычек. Я просто хотел иметь готовую функцию вместо того, чтобы писать что-то самому. Однако кода давно нет.
Лассе В. Карлсен

Ответы:


145

Нет встроенной функции, но вы можете сделать это довольно просто с пониманием генератора:

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

[Edit] В вашем обновлении вы указываете, что вам может потребоваться обработка цитирования. Это усложняет ситуацию, в зависимости от того, какой именно формат вы ищете (какие символы кавычек принимаются, какие escape-символы и т. Д.). Вы можете взглянуть на модуль csv, чтобы узнать, может ли он охватить ваш формат. Вот пример: (Обратите внимание, что API для этого примера немного неуклюжий, так как CSV предназначен для перебора последовательности записей, поэтому я делаю вызовы .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

1
Понятия не имею, почему AttributeError: '_csv.reader' object has no attribute 'next'меня бросает второй пример . Конечно, знал import csv.
Ёнджэ

@Brian Есть ли способ сохранить значения как целые, а не строковые?
ChasedByDeath

как можно сделать обратное @Brain
Джамиль Нойда

6

Это похоже на то, что вы хотели:

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

2
ломается если есть &или %на входе.
jfs

@jfs, но строка не содержит ни того, ни другого.
Вишал Сингх

@VishalSingh: большинство посетителей StackOverflow - из Google, поэтому здесь ответы предназначены не только для исходного автора, задавшего вопрос. Если бы я пришел сюда в поисках того, как выполнить синтаксический анализ «строки, разделенной точкой с запятой, в словарь в Python», тогда мои строки могли бы содержать &или %- по крайней мере, стоит упомянуть, что ответ не работает для таких строк.
jfs


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. В ОП конкретно говорится, что «такие небольшие решения обычно представляют собой минные поля, ожидающие своего появления», поэтому ему нужно встроенное или другое хорошо протестированное решение, и он приводит пример, который сломает ваш код.
abarnert

Ах, я этого не видел. Все еще. по-прежнему будет быстрее, чем все ваши решения, предварительно проанализировать их в основной строке до того, как произойдет итерация, и вызовет функцию замены тысячи раз. Я
обновлю

Я не уверен, как вы собираетесь его обработать. Но даже если вы это сделаете, это похоже на то, чего ОП боялся в простом решении. Вы уверены, что впереди нет других мин? Можете ли вы доказать это к удовлетворению ОП?
abarnert

Хорошо, теперь, когда я видел ваше редактирование ... Во-первых, s.replaceничего не делает; он просто возвращает новую строку, которую вы игнорируете. Во-вторых, даже если вы все поняли правильно ( s = s.replace…), это не решает проблему, а просто добавляет новую поверх нее. Попробуйте либо на моем примере, либо на OP.
abarnert

Спецификация явно включает обработку входного образца, который он упомянул в своем вопросе Name='Value1=2';. И ваш код не справляется с этим. И я не уверен, как бы вы санировали это, не разбирая его каким-либо образом, который будет таким же медленным, как urlparseили csvв первую очередь.
abarnert

-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'). Пробелы в строке (например, после каждой точки с запятой) игнорируются. Но обратите внимание, что строковые значения требуют заключения в кавычки.


Спасибо, upvote string.replace сработал. Не знаю, почему я не смог расстаться. Я сделал i = textcontrol.GetValue () в поле tc, затем o = i.split (';'), но не вывел строку, просто пожаловался на формат, в отличие от replace.
Iancovici

1
s.replace(';'-основанное решение не работает, если оно находится ;внутри указанного значения. eval - зло, и в этом случае он не нужен.
jfs
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.