Как преобразовать неверную строку в словарь?

У меня есть строка s (обратите внимание, что a и b ) не заключены в кавычки, поэтому ее нельзя напрямую оценить как ДИКТ ):

s = '{a:1,b:2}'

Я хочу преобразовать эту переменную в dict следующим образом:

{'a':1,'b':2}

Как я могу это сделать?

3
Хех. Теперь нам нужен BeautifulSoup для JSON.
добавлено автор kojiro, источник
Хех. Теперь нам нужен BeautifulSoup для JSON.
добавлено автор kojiro, источник
Я думаю, что у вас есть YAML.
добавлено автор Ben, источник
Я думаю, что у вас есть YAML.
добавлено автор Ben, источник
Я думаю, что у вас есть YAML.
добавлено автор Ben, источник
Почему вы используете такую ​​ужасную схему сериализации в первую очередь?
добавлено автор Fredrick Brennan, источник
Что сделал файл?
добавлено автор Fredrick Brennan, источник
Что сделал файл?
добавлено автор Fredrick Brennan, источник
Содержимое файла - это паук с сайта, обход контента, исходный формат - это
добавлено автор lu4nx, источник
Содержимое файла - это паук с сайта, обход контента, исходный формат - это
добавлено автор lu4nx, источник
Поскольку мой скрипт открывает файл, содержимое файла - это формат. Для облегчения я хочу прямо скрывать тип dict.
добавлено автор lu4nx, источник
Поскольку мой скрипт открывает файл, содержимое файла - это формат. Для облегчения я хочу прямо скрывать тип dict.
добавлено автор lu4nx, источник
Содержимое файла - это паук с сайта, обход контента, исходный формат - это
добавлено автор lu4nx, источник

10 ответы

Это будет работать с вашим примером:

import ast
def elem_splitter(s):
    return s.split(':',1)

s = '{a:1,b:2}'
s_no_braces = s.strip()[1:-1] #s.translate(None,'{}') is more elegant, but can fail if you can have strings with '{' or '}' enclosed.
elements = (elem_splitter(ss) for ss in s_no_braces.split(','))
d = dict((k,ast.literal_eval(v)) for k,v in elements)

Обратите внимание, что это произойдет, если у вас есть строка, отформатированная как:

'{s:"foo,bar",ss:2}'  #comma in string is a problem for this algorithm

или:

'{s,ss:1,v:2}' 

но он будет передавать строку как:

'{s ss:1,v:2}' #{"s ss":1, "v":2}

Вы также можете немного изменить elem_splitter , в зависимости от ваших потребностей:

def elem_splitter(s):
    k,v = s.split(':',1)
    return k.strip(),v # maybe `v.strip() also?`

* Кто-то еще может приготовить лучший пример, используя больше модуля ast , но я не очень хорошо знаю его внутренности, поэтому я сомневаюсь, что у меня будет время, чтобы ответить на этот вопрос.

5
добавлено
очень хорошо, спасибо :)
добавлено автор lu4nx, источник

Это будет работать с вашим примером:

import ast
def elem_splitter(s):
    return s.split(':',1)

s = '{a:1,b:2}'
s_no_braces = s.strip()[1:-1] #s.translate(None,'{}') is more elegant, but can fail if you can have strings with '{' or '}' enclosed.
elements = (elem_splitter(ss) for ss in s_no_braces.split(','))
d = dict((k,ast.literal_eval(v)) for k,v in elements)

Обратите внимание, что это произойдет, если у вас есть строка, отформатированная как:

'{s:"foo,bar",ss:2}'  #comma in string is a problem for this algorithm

или:

'{s,ss:1,v:2}' 

но он будет передавать строку как:

'{s ss:1,v:2}' #{"s ss":1, "v":2}

Вы также можете немного изменить elem_splitter , в зависимости от ваших потребностей:

def elem_splitter(s):
    k,v = s.split(':',1)
    return k.strip(),v # maybe `v.strip() also?`

* Кто-то еще может приготовить лучший пример, используя больше модуля ast , но я не очень хорошо знаю его внутренности, поэтому я сомневаюсь, что у меня будет время, чтобы ответить на этот вопрос.

5
добавлено
очень хорошо, спасибо :)
добавлено автор lu4nx, источник

Это будет работать с вашим примером:

import ast
def elem_splitter(s):
    return s.split(':',1)

s = '{a:1,b:2}'
s_no_braces = s.strip()[1:-1] #s.translate(None,'{}') is more elegant, but can fail if you can have strings with '{' or '}' enclosed.
elements = (elem_splitter(ss) for ss in s_no_braces.split(','))
d = dict((k,ast.literal_eval(v)) for k,v in elements)

Обратите внимание, что это произойдет, если у вас есть строка, отформатированная как:

'{s:"foo,bar",ss:2}'  #comma in string is a problem for this algorithm

или:

'{s,ss:1,v:2}' 

но он будет передавать строку как:

'{s ss:1,v:2}' #{"s ss":1, "v":2}

Вы также можете немного изменить elem_splitter , в зависимости от ваших потребностей:

def elem_splitter(s):
    k,v = s.split(':',1)
    return k.strip(),v # maybe `v.strip() also?`

* Кто-то еще может приготовить лучший пример, используя больше модуля ast , но я не очень хорошо знаю его внутренности, поэтому я сомневаюсь, что у меня будет время, чтобы ответить на этот вопрос.

5
добавлено
очень хорошо, спасибо :)
добавлено автор lu4nx, источник

Поскольку ваша строка неверна, так как json и Python dict так что вы не можете использовать json.loads, а не ast.literal_eval, чтобы напрямую преобразовывать данные.

В этом конкретном случае вам придется вручную перевести его в словарь Python, познав входные данные

>>> foo = '{a:1,b:2}'
>>> dict(e.split(":") for e in foo.translate(None,"{}").split(","))
{'a': '1', 'b': '2'}

Как обновлено Тимом, и моя близорукость я пропустил тот факт, что значения должны быть целыми, вот альтернативная реализация

>>> {k: int(v) for e in foo.translate(None,"{}").split(",") 
     for k, v in [e.split(":")]}
{'a': 1, 'b': 2}
2
добавлено
Обратите внимание, что теперь у вас есть '1' , где у вас должен быть 1 .
добавлено автор Tim Pietzcker, источник

Поскольку ваша строка неверна, так как json и Python dict так что вы не можете использовать json.loads, а не ast.literal_eval, чтобы напрямую преобразовывать данные.

В этом конкретном случае вам придется вручную перевести его в словарь Python, познав входные данные

>>> foo = '{a:1,b:2}'
>>> dict(e.split(":") for e in foo.translate(None,"{}").split(","))
{'a': '1', 'b': '2'}

Как обновлено Тимом, и моя близорукость я пропустил тот факт, что значения должны быть целыми, вот альтернативная реализация

>>> {k: int(v) for e in foo.translate(None,"{}").split(",") 
     for k, v in [e.split(":")]}
{'a': 1, 'b': 2}
2
добавлено
Обратите внимание, что теперь у вас есть '1' , где у вас должен быть 1 .
добавлено автор Tim Pietzcker, источник

Поскольку ваша строка неверна, так как json и Python dict так что вы не можете использовать json.loads, а не ast.literal_eval, чтобы напрямую преобразовывать данные.

В этом конкретном случае вам придется вручную перевести его в словарь Python, познав входные данные

>>> foo = '{a:1,b:2}'
>>> dict(e.split(":") for e in foo.translate(None,"{}").split(","))
{'a': '1', 'b': '2'}

Как обновлено Тимом, и моя близорукость я пропустил тот факт, что значения должны быть целыми, вот альтернативная реализация

>>> {k: int(v) for e in foo.translate(None,"{}").split(",") 
     for k, v in [e.split(":")]}
{'a': 1, 'b': 2}
2
добавлено
Обратите внимание, что теперь у вас есть '1' , где у вас должен быть 1 .
добавлено автор Tim Pietzcker, источник
import re,ast
regex = re.compile('([a-z])')
ast.literal_eval(regex.sub(r'"\1"', s))

<Сильный> из

{'a': 1, 'b': 2}

EDIT: If you happen to have something like {foo1:1,bar:2} add an additional capture group to the regex:

regex = re.compile('(\w+)(:)')
ast.literal_eval(regex.sub(r'"\1"\2', s))
2
добавлено
@root - Да, это сработает (с соответствующими исходными строками в компиляции) - если только целые числа не будут разрешены в качестве словарных клавиш, но ни одно решение не будет правильно исправлено, но я не думаю. Я подниму это: :) (+1)
добавлено автор mgilson, источник
Как насчет строки формы: {foo1: 1} ? Вы можете сделать это с помощью "\ w +" , но это нехорошо, так как это также укажет 1 .
добавлено автор mgilson, источник
@mgilson - вы можете улучшить ссылку на regex и группу захвата: change re.compile ('(\ w +) (:)') и regex.sub (r '"\ 1" \ 2 ', s) , и все должно быть в порядке.
добавлено автор root, источник
вы код очень прост, thks :)
добавлено автор lu4nx, источник
import simplejson
s = '{a:1,b:2}'
a = simplejson.loads(s)
print a
2
добавлено
В моих установках Python я даже не догадываюсь: ImportError: нет модуля с именем simplejson .
добавлено автор Tim Pietzcker, источник
@TimPietzcker У меня он установлен, потому что я часто запускаю старые сценарии, которые import он. Для нового кода правильным способом является, безусловно, import json .
добавлено автор Fredrick Brennan, источник
-1, simplejson.decoder.JSONDecodeError: Ожидание имени свойства: строка 1 столбец 1 (char 1)
добавлено автор Fredrick Brennan, источник
420 повысить JSONDecodeError («Нет объекта JSON может быть декодирован», s, idx) JSONDecodeError: Ожидание имени свойства: строка 1 столбец 1 (символ 1)
добавлено автор lu4nx, источник
import simplejson
s = '{a:1,b:2}'
a = simplejson.loads(s)
print a
2
добавлено
В моих установках Python я даже не догадываюсь: ImportError: нет модуля с именем simplejson .
добавлено автор Tim Pietzcker, источник
@TimPietzcker У меня он установлен, потому что я часто запускаю старые сценарии, которые import он. Для нового кода правильным способом является, безусловно, import json .
добавлено автор Fredrick Brennan, источник
-1, simplejson.decoder.JSONDecodeError: Ожидание имени свойства: строка 1 столбец 1 (char 1)
добавлено автор Fredrick Brennan, источник
420 повысить JSONDecodeError («Нет объекта JSON может быть декодирован», s, idx) JSONDecodeError: Ожидание имени свойства: строка 1 столбец 1 (символ 1)
добавлено автор lu4nx, источник

Вы можете сделать это просто с этим:

s = "{a:1,b:2}"
content = s[s.index("{")+1:s.index("}")]
to_int = lambda x: int(x) if x.isdigit() else x
d = dict((to_int(i) for i in pair.split(":", 1)) for pair in content.split(","))

Для простоты я исключил обработку исключений, если строка не содержит допустимой спецификации, а также эта версия не разделяет пробелы, которые вы можете захотеть. Если интерпретация, которую вы предпочитаете, состоит в том, что ключ всегда является строкой, а значение всегда является int , то это еще проще:

s = "{a:1,b:2}"
content = s[s.index("{")+1:s.index("}")]
d = dict((int(pair[0]), pair[1].strip()) for pair in content.split(","))

В качестве бонуса эта версия также удаляет пробелы из ключа, чтобы показать, насколько это просто.

0
добавлено
Python
Python
7 654 участник(ов)

Уютный чат для профессионалов, занимающихся поиском питоньих мудростей. Как не получить бан: https://t.me/ru_python/577926

Python beginners
Python beginners
4 449 участник(ов)

Вопросы про Python для чайников. Cпам и троллинг неприемлем. Не злоупотребляйте стикерами. Частозадаваемые вопросы: https://github.com/ru-python-beginners/faq/blob/master/README.md Статистика тут: https://grstats.me/chat/x4qym2k5uvfkr3al6at7

pro.python
pro.python
1 090 участник(ов)

Сообщество разработчиков под Python Создатель: @rodgelius

Rude Python
Rude Python
971 участник(ов)

Python без „девочек”, здесь матерятся и унижают Django. Not gay friendly. Правила: t.me/rudepython/114107 @rudepython | t.me/rudepython

rupython
rupython
509 участник(ов)

Группа создана с целью оперативного получения ответов на возникающие вопросы по разработке на яп python, смежные темы, а также человеческого общения. Приветствую!

Python-programming
Python-programming
266 участник(ов)

Чат группы вконтакте https://vk.com/python_community