LINUX.ORG.RU

Перевести строку в словарь

 


0

1

Есть строка, вывод одной команды в виде:

key1: value1
key2: value2

И так далее. Как её наименьшими усилиями перевести в словарь? Гугл советует какие-то дикие и устаревшие варианты типа задействования eval. Вариант с json у меня почему-то не работает.

Может, через цикл прогнать, или есть какой-нибудь подходящий генератор словарей?

Deleted

Вариант с json у меня почему-то не работает.

Потому что это не JSON. С YAML бы сработало.

>>> import yaml
>>> s = "key1: value1\nkey2: value2"
>>> yaml.safe_load(s)
{'key2': 'value2', 'key1': 'value1'}
>>> 

На твой страх и риск. :-D

i-rinat ★★★★★
()
Ответ на: комментарий от no-such-file

он спецом написал однострочником. если развернуть по pep8, задействовать распаковку переменных, всё отлично читаемо будет

eternal_sorrow ★★★★★
()
Ответ на: комментарий от eternal_sorrow

Пустых строк и строк без двоеточия нет, но есть разделители в строках, которые выравнивают values

Deleted
()
Ответ на: комментарий от eternal_sorrow

Вроде только пробелы, потому что табы я пробовал удалять - ничего не изменилось. Хотя, может, ещё какие-нибудь символы бывают.

Deleted
()
Ответ на: комментарий от Deleted

Потому что для парсинга простого формата используется парсер YAML. Если ты полностью контролируешь ввод, на такое можно закрыть глаза. Но если вдруг данные могут начать приходить неконтролируемые, а такое всегда случается внезапно и неожиданно, могут быть сюрпризы.

По-хорошему, нужно сделать парсер, который понимает ровно этот формат и ничего больше. Тем более, тут это не так уж и сложно. Цикл, пара split'ов, trim'ы. И ещё проверки на всякие краевые случаи вроде пустой строки.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Это вывод утилиты, и если её авторы вздумают изменить формат вывода, то мне кажется, что мой самописный парсер сломается с таким же успехом)

Deleted
()
Ответ на: комментарий от no-such-file

примерно так:

input_string = """\
key1: value1
key2: value2"""

rows = input_string.split('\n')
pairs = [row.split(':') for row in rows]
result = {key.strip(): value.strip() for key, value in pairs}
   

eternal_sorrow ★★★★★
()
Последнее исправление: eternal_sorrow (всего исправлений: 2)
Ответ на: комментарий от eternal_sorrow
>>> input_string = """\
... key1: value1
... key2: value2"""
>>> result = dict([item.split(':') for item in input_string.split('\n')])
>>> print(result)
{'key2': ' value2', 'key1': ' value1'}

Или, я чего-то не понимаю? Учусь)

hanharr
()
Ответ на: комментарий от hanharr

ты не знаешь, сколько там пробелов на самом деле. а могут быть вообще табы. а если знаешь, то этот вариант вполне годится

eternal_sorrow ★★★★★
()
Последнее исправление: eternal_sorrow (всего исправлений: 1)
Ответ на: комментарий от slovazap

Можно filter(None, input.splitlines()) чтобы пустые строки вырезать. А можно input.splitlines() if ':' in line]

pawnhearts ★★★★★
()
Ответ на: комментарий от pawnhearts

мы тут в написании однострочников соревнуемся? понятно, что это можно сделать, вопрос зачем? на деле если ты такой код напишешь где нибудь в проекте, тебя завернут на ревью сходу. он не соответствует ни pep8 ни здравому смыслу, совершенно нечитаемый и неподдерживаемый

eternal_sorrow ★★★★★
()
Ответ на: комментарий от no-such-file

Молодому поколению уже код на педонобейсике кажется сложным, куда мы катимся.

anonymous
()
def str_to_dict(lines: str) -> dict:
    sep = ': '
    result = {}
    for line in lines.split('\n'):
        sep_count = line.count(sep)
        if not sep_count:
            continue
        key, value = line.split(sep, 1)
        if sep_count != 1 or not key:
            print('Warning, ignore line: {}'.format(repr(line)))
            continue
        result[key] = value
    return result
KillTheCat ★★★★★
()
Ответ на: комментарий от slovazap

Если строка key содержит ':', то твой код все поломает. Сначала нужно хотя бы подсчитать количество вхождений разделителя ключа/значения в строке.

anonymous
()

Только вчера это искал. Доеду до работы отпишусь. Кажется ast.literal использовал.

Но там строка должна иметь вид {'key1': val1, 'key2': val2}. То есть остаётся сформировать строку такого вида или та функция ещё что-то поддерживает.

grem ★★★★★
()
Ответ на: комментарий от KillTheCat

Для любителей однострочников:

r = {e[0]: e[1] for e in [e.split(': ') for e in s.split('\n')] if len(e) == 2 and e[0]}
KillTheCat ★★★★★
()
Ответ на: комментарий от Deleted

type hint, но должно быть так

from typing import Dict

def str_to_dict(lines: str) -> Dict[str, str]:

pawnhearts ★★★★★
()
Ответ на: комментарий от anonymous

key не может содержать : иначе не будет возможности понять где именно находится разделитель, а про эскейпинг или квотинг в исходном сообщении нет ни слова. Так что за придумывание несуществующих требований и переусложнение вам два. А вот в value : ничего не сломает.

slovazap ★★★★★
()
Ответ на: комментарий от slovazap

Забавная защитная реакций. Ставить оценку тому, кто указал на твою ошибку. Легче стало?

anonymous
()
Ответ на: комментарий от anonymous

всегда больше

К великому счастью. «Хорошие» псевдопредусмотрительные недокодеры которые невешивают монструозные фреймворки на ровном месте давно уничтожили бы IT будь их хоть сколько либо значительное количество.

slovazap ★★★★★
()
Ответ на: комментарий от eternal_sorrow

например, что-то такое:

molar_mass = {'O2': 31.999, 'N2': 28.0134}
mole_frac =  {'O2': 0.21, 'N2': 0.79}

W = sum(v*mole_frac[k] for k, v in molar_mass.items() if k in mole_frac)

grem ★★★★★
()
Ответ на: комментарий от grem

почти норм. только однобуквенные переменные не ок. ну и соответственно в строку у тебя с нормальными именами переменных не влезет. можно конечно сделать так:

W = sum(
   value * mole_frac[key]
   for key, value in molar_mass.items()
   if key in mole_frac
)

eternal_sorrow ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.