내가 사용하고 파이썬 2ASCII 인코딩 텍스트 파일 에서 JSON을 구문 분석하기 위해 를 있습니다.
json
또는 로이 파일을로드하면 simplejson
모든 문자열 값이 문자열 객체 대신 유니 코드 객체로 캐스팅됩니다. 문제는 문자열 객체 만 허용하는 일부 라이브러리에서 데이터를 사용해야한다는 것입니다. 나는 라이브러리를 변경할 수 없습니다 도를 업데이트합니다.
유니 코드가 아닌 문자열 객체를 얻을 수 있습니까?
예
>>> import json
>>> original_list = ['a', 'b']
>>> json_list = json.dumps(original_list)
>>> json_list
'["a", "b"]'
>>> new_list = json.loads(json_list)
>>> new_list
[u'a', u'b'] # I want these to be of type `str`, not `unicode`
최신 정보
이 질문은 오래 전에 파이썬 2 에 갇혀있을 때 물었 습니다 . 오늘날의 쉽고 깨끗한 솔루션 중 하나는 최신 버전의 Python (예 : Python 3 이상 )을 사용하는 것 입니다.
답변
솔루션 object_hook
import json
def json_load_byteified(file_handle):
return _byteify(
json.load(file_handle, object_hook=_byteify),
ignore_dicts=True
)
def json_loads_byteified(json_text):
return _byteify(
json.loads(json_text, object_hook=_byteify),
ignore_dicts=True
)
def _byteify(data, ignore_dicts = False):
# if this is a unicode string, return its string representation
if isinstance(data, unicode):
return data.encode('utf-8')
# if this is a list of values, return list of byteified values
if isinstance(data, list):
return [ _byteify(item, ignore_dicts=True) for item in data ]
# if this is a dictionary, return dictionary of byteified keys and values
# but only if we haven't already byteified it
if isinstance(data, dict) and not ignore_dicts:
return {
_byteify(key, ignore_dicts=True): _byteify(value, ignore_dicts=True)
for key, value in data.iteritems()
}
# if it's anything else, return it in its original form
return data
사용법 예 :
>>> json_loads_byteified('{"Hello": "World"}')
{'Hello': 'World'}
>>> json_loads_byteified('"I am a top-level string"')
'I am a top-level string'
>>> json_loads_byteified('7')
7
>>> json_loads_byteified('["I am inside a list"]')
['I am inside a list']
>>> json_loads_byteified('[[[[[[[["I am inside a big nest of lists"]]]]]]]]')
[[[[[[[['I am inside a big nest of lists']]]]]]]]
>>> json_loads_byteified('{"foo": "bar", "things": [7, {"qux": "baz", "moo": {"cow": ["milk"]}}]}')
{'things': [7, {'qux': 'baz', 'moo': {'cow': ['milk']}}], 'foo': 'bar'}
>>> json_load_byteified(open('somefile.json'))
{'more json': 'from a file'}
어떻게 작동하며 왜 사용합니까?
마크 애 머리의 기능 은이 보다 짧고 명확합니다. 그렇다면 요점은 무엇입니까? 왜 그것들을 사용하고 싶습니까?
순수한 성능 . Mark의 답변은 먼저 유니 코드 문자열로 JSON 텍스트를 완전히 디코딩 한 다음 디코딩 된 전체 값을 반복하여 모든 문자열을 바이트 문자열로 변환합니다. 이것은 바람직하지 않은 몇 가지 영향을 미칩니다.
- 전체 디코딩 구조의 복사본이 메모리에 생성됩니다.
- JSON 객체가 실제로 깊게 중첩되어 있으면 (500 레벨 이상) Python의 최대 재귀 깊이에 도달합니다
이 답변 object_hook
은 json.load
및 매개 변수를 사용하여 이러한 성능 문제를 모두 완화합니다 json.loads
. 에서 워드 프로세서 :
object_hook
(adict
) 객체 리터럴 디코딩 결과로 호출되는 선택적 함수입니다 . 대신에 object_hook의 반환 값이 사용됩니다dict
. 이 기능은 커스텀 디코더를 구현하는 데 사용할 수 있습니다
다른 딕셔너리에 많은 레벨이 중첩 된 딕셔너리 object_hook
는 디코딩 될 때 전달되기 때문에 , 그 시점에서 그 안에 문자열이나리스트를 바이트 화하고 나중에 깊은 재귀가 필요하지 않도록 할 수 있습니다.
Mark의 답변은 object_hook
중첩 된 사전으로 되풀이되므로 그대로 사용하기에 적합하지 않습니다 . 우리는이 대답에 그 재귀 방지 ignore_dicts
에 대한 매개 변수를 _byteify
항상 그것에 전달되는, 제외 하면 object_hook
이 새로운 전달 dict
byteify 할 수 있습니다. ignore_dicts
플래그는 말한다_byteify
무시 dict
이미 byteified 된 이후들.
마지막으로, 디코딩되는 JSON 텍스트가 최상위 레벨에 없는 경우를 처리 하거나 반환 된 결과에 대해 (with )를 구현 json_load_byteified
하고 json_loads_byteified
호출 합니다._byteify
ignore_dicts=True
json.load
json.loads
dict
답변
여기에 좋은 대답이 있지만 키와 값을 유형 대신 유형 문자열 로 제공하기 때문에 PyYAML 을 사용하여 JSON 파일을 구문 분석했습니다 . JSON은 YAML의 하위 집합이기 때문에 잘 작동합니다.str
unicode
>>> import json
>>> import yaml
>>> list_org = ['a', 'b']
>>> list_dump = json.dumps(list_org)
>>> list_dump
'["a", "b"]'
>>> json.loads(list_dump)
[u'a', u'b']
>>> yaml.safe_load(list_dump)
['a', 'b']
노트
그래도주의해야 할 사항 :
-
모든 항목이 ASCII로 인코딩 되어 있기 때문에 문자열 객체를 얻습니다 . 유니 코드로 인코딩 된 항목을 사용하면 유니 코드 개체 로 다시 가져올 수 있습니다 . 변환이 없습니다!
-
PyYAML의
safe_load
기능을 사용해야합니다 (아마도 항상) . JSON 파일을로드하는 데 사용하는 경우load
어쨌든 함수 의 “추가 기능”이 필요하지 않습니다 . -
당신은 (그리고 사양의 1.2 버전에 대한 더 많은 지원이있는 YAML 파서하려면 매우 낮은 번호를 올바르게 구문 분석 ) 시도 Ruamel YAML을 :
pip install ruamel.yaml
그리고import ruamel.yaml as yaml
내 시험에 필요한 모든 I이었다.
변환
명시된 바와 같이, 전환이 없습니다! ASCII 값만 처리 할 수없고 대부분의 시간을 확신 할 수없는 경우 변환 함수를 사용하는 것이 좋습니다 .
나는 Mark Amery 의 제품을 몇 번 사용했지만 훌륭하게 작동하고 사용하기 쉽습니다. object_hook
큰 파일의 성능이 향상 될 수 있으므로 비슷한 기능을 대신 사용할 수도 있습니다. 이에 대한 Mirec Miskuf 의 약간 더 관련된 답변을 참조하십시오 .
답변
json 모듈 함수가 유니 코드 문자열 대신 바이트 문자열을 반환하도록하는 기본 제공 옵션이 없습니다. 그러나이 짧고 간단한 재귀 함수는 디코딩 된 모든 JSON 객체를 유니 코드 문자열 사용에서 UTF-8로 인코딩 된 바이트 문자열로 변환합니다.
def byteify(input):
if isinstance(input, dict):
return {byteify(key): byteify(value)
for key, value in input.iteritems()}
elif isinstance(input, list):
return [byteify(element) for element in input]
elif isinstance(input, unicode):
return input.encode('utf-8')
else:
return input
json.load
또는 a에서 얻은 출력에서 이것을 호출하십시오.json.loads
호출 호출하십시오.
몇 가지 메모 :
- 이전 파이썬 2.6를 지원하거나, 교체
return {byteify(key): byteify(value) for key, value in input.iteritems()}
로return dict([(byteify(key), byteify(value)) for key, value in input.iteritems()])
사전 함축 파이썬 2.7까지 지원되지 되었기 때문에. - 이 답변은 전체 디코딩 된 객체를 통해 반복되므로,
object_hook
또는object_pairs_hook
매개 변수 를 매우 신중하게 사용하여 피할 수있는 몇 가지 바람직하지 않은 성능 특성이 있습니다 . Mirec Miskuf의 대답 은 지금까지 이것을 올바르게 뽑아내는 유일한 방법입니다. 결과적으로 내 접근 방식보다 훨씬 더 복잡합니다.
답변
object_hook
매개 변수를 사용하여 json.loads
변환기를 전달할 수 있습니다 . 사실 후에 변환을 수행 할 필요가 없습니다. json
모듈은 항상 통과 할 object_hook
경우에만 dicts을, 당신은 중첩 된 dicts에 자신을 재귀 할 필요가 없습니다 그것은 반복적으로 중첩 dicts로 전달됩니다. 유니 코드 문자열을 Wells 쇼와 같은 숫자로 변환하지는 않을 것이라고 생각합니다. 유니 코드 문자열 인 경우 JSON 파일에서 문자열로 인용되었으므로 문자열이거나 파일이 잘못되었습니다.
또한, 나는 같은 일을 피하려고 것 str(val)
A의 unicode
객체를. value.encode(encoding)
외부 라이브러리가 기대하는 바에 따라 유효한 인코딩을 사용해야합니다 .
예를 들어,
def _decode_list(data):
rv = []
for item in data:
if isinstance(item, unicode):
item = item.encode('utf-8')
elif isinstance(item, list):
item = _decode_list(item)
elif isinstance(item, dict):
item = _decode_dict(item)
rv.append(item)
return rv
def _decode_dict(data):
rv = {}
for key, value in data.iteritems():
if isinstance(key, unicode):
key = key.encode('utf-8')
if isinstance(value, unicode):
value = value.encode('utf-8')
elif isinstance(value, list):
value = _decode_list(value)
elif isinstance(value, dict):
value = _decode_dict(value)
rv[key] = value
return rv
obj = json.loads(s, object_hook=_decode_dict)
답변
json은 문자열 객체와 유니 코드 객체 사이에 차이가 없기 때문입니다. 그들은 모두 자바 스크립트의 문자열입니다.
JSON이 유니 코드 객체를 반환하는 것이 옳다고 생각 합니다 . 사실, 자바 스크립트 문자열 은 실제로 unicode
객체 (즉, JSON (javascript) 문자열은 모든 종류 의 유니 코드 문자를 저장할 수 있음 )이므로 객체를 덜 받아들이지 않으므로 JSON unicode
에서 문자열을 변환 할 때 객체 를 만드는 것이 좋습니다 . 라이브러리는 원하는 인코딩을 추측해야하기 때문에 일반 문자열은 적합하지 않습니다.
unicode
어디에서나 문자열 객체 를 사용하는 것이 좋습니다 . 따라서 가장 좋은 방법은 라이브러리를 업데이트하여 유니 코드 객체를 처리 할 수 있도록하는 것입니다.
그러나 바이트 문자열을 정말로 원한다면 결과를 원하는 인코딩으로 인코딩하십시오.
>>> nl = json.loads(js)
>>> nl
[u'a', u'b']
>>> nl = [s.encode('utf-8') for s in nl]
>>> nl
['a', 'b']
답변
쉬운 해결 방법이 있습니다.
TL; DR- ast.literal_eval()
대신 사용하십시오 json.loads()
. 모두 ast
와 json
표준 라이브러리에 있습니다.
‘완벽한’대답은 아니지만 계획에서 유니 코드를 완전히 무시하려는 경우에는 한 가지 결과를 얻을 수 있습니다. 파이썬 2.7에서
import json, ast
d = { 'field' : 'value' }
print "JSON Fail: ", json.loads(json.dumps(d))
print "AST Win:", ast.literal_eval(json.dumps(d))
제공합니다 :
JSON Fail: {u'field': u'value'}
AST Win: {'field': 'value'}
일부 객체가 실제로 유니 코드 문자열 인 경우 더 털이 있습니다. 완전한 대답은 빨리 털이 나옵니다.
답변
Mike Brennan의 대답 은 가깝지만 전체 구조를 다시 횡단 할 이유는 없습니다. object_hook_pairs
(Python 2.7+) 매개 변수 를 사용하는 경우 :
object_pairs_hook
정렬 된 쌍의 목록으로 디코딩 된 객체 리터럴의 결과와 함께 호출되는 선택적 함수입니다. 의 반환 값이object_pairs_hook
대신 사용됩니다dict
. 이 기능은 키와 값 쌍이 디코딩collections.OrderedDict
되는 순서 (예를 들어 삽입 순서를 기억할 것) 에 의존하는 사용자 정의 디코더를 구현하는 데 사용할 수 있습니다 .object_hook
또한 정의 된 경우object_pairs_hook
우선 순위를 갖습니다.
이를 사용하면 각 JSON 객체를 사용할 수 있으므로 재귀 필요없이 디코딩을 수행 할 수 있습니다.
def deunicodify_hook(pairs):
new_pairs = []
for key, value in pairs:
if isinstance(value, unicode):
value = value.encode('utf-8')
if isinstance(key, unicode):
key = key.encode('utf-8')
new_pairs.append((key, value))
return dict(new_pairs)
In [52]: open('test.json').read()
Out[52]: '{"1": "hello", "abc": [1, 2, 3], "def": {"hi": "mom"}, "boo": [1, "hi", "moo", {"5": "some"}]}'
In [53]: json.load(open('test.json'))
Out[53]:
{u'1': u'hello',
u'abc': [1, 2, 3],
u'boo': [1, u'hi', u'moo', {u'5': u'some'}],
u'def': {u'hi': u'mom'}}
In [54]: json.load(open('test.json'), object_pairs_hook=deunicodify_hook)
Out[54]:
{'1': 'hello',
'abc': [1, 2, 3],
'boo': [1, 'hi', 'moo', {'5': 'some'}],
'def': {'hi': 'mom'}}
를 사용할 때 모든 객체가 후크에 전달되므로 후크를 재귀 적으로 호출 할 필요가 없습니다 object_pairs_hook
. 리스트에 신경 쓸 필요는 있지만, 보시다시피,리스트 내의 객체는 올바르게 변환 될 것이며, 그것을하기 위해 재귀 할 필요는 없습니다.
편집 : 동료는 Python2.6에 object_hook_pairs
. 파이썬 2.6을 아주 조금만 변경하여 사용할 수 있습니다. 위의 후크에서 다음을 변경하십시오.
for key, value in pairs:
에
for key, value in pairs.iteritems():
그런 다음 object_hook
대신 사용하십시오 object_pairs_hook
.
In [66]: json.load(open('test.json'), object_hook=deunicodify_hook)
Out[66]:
{'1': 'hello',
'abc': [1, 2, 3],
'boo': [1, 'hi', 'moo', {'5': 'some'}],
'def': {'hi': 'mom'}}
object_pairs_hook
JSON 객체의 각 객체에 대해 하나의 적은 사전이 인스턴스화되는 결과를 사용하면 큰 문서를 구문 분석하는 경우 가치가있을 수 있습니다.