Розбиття рядка, розділеного крапкою з комою, на словник, на 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використовується escape, використовуються як одинарні, так і подвійні лапки)?
jfs

Цьому моєму питанню більше 6 років, код, який це стосується, давно замінений :) І ні, він не вимагав підтримки цитат. Я просто хотів мати попередньо побудовану функцію, замість того, щоб писати щось самостійно. Однак код давно зник.
Лассе В. Карлсен,

Відповіді:


144

Тут немає вбудованого, але ви можете зробити це досить просто, зрозумівши генератор:

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

[Редагувати] З вашого оновлення ви вказуєте, що, можливо, вам доведеться обробляти цитування. Це ускладнює речі, залежно від того, який саме формат ви шукаєте (які символи котирувань приймаються, які символи символів втечі тощо). Можливо, ви захочете поглянути на модуль 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.
Youngjae

@Brian Чи є спосіб зберігати значення як ціле, а не як рядок?
ChasedByDeath

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

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(як у Кайла) все зрозумієте, тоді як ваша підніме a ValueError. В ОП конкретно сказано, що "такі дрібні рішення зазвичай є шахтними полями, які чекають", саме тому він хоче вбудоване або інше добре перевірене рішення, і він наводить приклад, який зламає ваш код.
abarnert

Ааа, я цього не бачив. досі. все одно було б швидше, ніж усі ваші рішення, попередньо проаналізувати рішення в основному рядку до того, як відбудеться ітерація та тисяча разів викликати функцію заміни. Буду оновлювати
easytiger

Я не впевнений, як ти збираєшся це підготувати. Але навіть якщо ви це зробите, це здається саме тим, чого ОП боявся у простому рішенні. Ви впевнені, що попереду інших шахт немає? Чи можете ви довести це на задоволення ОП?
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'). Пробіли в рядку (наприклад, після кожної крапки з комою) ігноруються. Але зверніть увагу, що значення рядків вимагають цитування.


Дякую, підтримка 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.