simplejson:加载西班牙字符 -- utf-8
我正在尝试用Python的simplejson
加载一些地理数据。
<!-- language: lang-py -->
string = file("prCounties.txt","r").read().decode('utf-8')
d = simplejson.loads(string)
这个文本文件里有个波浪号,正确的单词应该是Añasco,但它显示成了u"A\xf1asco"
,而SimpleJson无法解析这个。数据来源是一个来自GitHub的geoJson文件。
{"type": "FeatureCollection", "properties": {"kind": "state", "state": "PR"}, "features": [[{"geometry": {"type": "MultiPolygon", "coordinates": [[[[-67.122, 18.3239], [-67.0508, 18.3075], [-67.0398, 18.291], [-67.0837, 18.2527], [-67.122, 18.2417], [-67.1603, 18.2746], [-67.1877, 18.2691], [-67.2261, 18.2965], [-67.1822, 18.3129], [-67.1275, 18.3184]]]]}, "type": "Feature", "properties": {"kind": "county", "name": u"A\xf1asco", "state": "PR"}}]]}
Python给我报了个错:simplejson.decoder.JSONDecodeError: Expecting object
。
我用来从GitHub加载数据的脚本生成了prCounties.txt
。变量counties
是一个字符串列表,包含了相关GEOjson数据的位置。
很明显,这样保存数据是不对的:
<!-- language: lang-py -->
countyGeo = [ ]
for x in counties:
d = simplejson.loads(urllib.urlopen("https://raw.github.com/johan/world.geo.json/master/countries/USA/PR/%s" % (x)).read())
countyGeo += [ d["features"][0]]
d["features"][0]=countyGeo
file("prCounties.txt", "w").write(str(d))
编辑:在最后一行,我把str
替换成了simplejson.dumps
。我想这样编码应该没问题了。
file("prCounties.txt", "w").write(simplejson.dumps(d))
3 个回答
你需要在你的 prCounties.txt 文件中去掉 "u" 这个字母(之前已经提到过了)。然后你可以使用下面的代码,这段代码可以很好地创建一个叫 "string" 的变量,这个变量的格式是简单的 json.loads() 函数可以识别的:
import simplejson
string = file("prCounties.txt", "r").read().decode("string-escape")
string = unicode(string, "latin-1")
simplejson.loads(string)
你的输入文件不是有效的JSON格式。在字符串"A\xf1asco"
前面有一个u
,这是Python的语法,而不是JSON的语法。正确的写法应该是:
"name":"A\xf1asco",
这样写就可以了:
>>> import json
>>> json.loads(u'{"name":"A\xf1asco"}')
{u'name': u'A\xf1asco'}
这里有两个问题。首先:
string = file("prCounties.txt","r").read().decode('utf-8')
你为什么要解码它呢?JSON明确规定使用UTF-8字符串。这是JSON定义的一部分。虽然simplejson
可以处理Unicode字符串,让使用起来简单一些,但它实际上是通过把这些字符串重新编码为UTF-8来处理它们的。那么……为什么一开始不就直接用UTF-8呢?
更重要的是,你的数据是从哪里来的?如果prCounties.txt
里面有u"Añasco"
,那就不是JSON格式。你不能把某个东西编码成一种标准,然后再解码成完全不同的标准,仅仅因为它们看起来相似。
举个例子,如果你用open('prCounties.txt', 'w').write(repr(my_dict))
写入数据,那么你必须用Python的repr
解析器来读取它(可能需要用ast.literal_eval
,或者你可能需要自己写一个)。
或者,如果你想把数据解析成JSON格式,最好一开始就以JSON格式写入。
根据你的评论,这些数据是从https://raw.github.com/johan/world.geo.json/master/countries/USA/PR/Añasco.geo.json读取的。
那个网址的原始内容是:
{"type":"FeatureCollection","properties":{"kind":"state","state":"PR"},"features":[
{"type":"Feature","properties":{"kind":"county","name":"Añasco","state":"PR"},"geometry":{"type":"MultiPolygon","coordinates":[[[[-67.1220,18.3239],[-67.0508,18.3075],[-67.0398,18.2910],[-67.0837,18.2527],[-67.1220,18.2417],[-67.1603,18.2746],[-67.1877,18.2691],[-67.2261,18.2965],[-67.1822,18.3129],[-67.1275,18.3184]]]]}}
]}
你会注意到那里没有"name": u"Añasco"
(或者"name": u"A\xf1asco"
,或者类似的东西)。你只需调用read
就可以读取这个内容——不需要从UTF-8解码什么的——然后直接传给simplejson.loads
就可以正常工作:
$ curl -O https://raw.github.com/johan/world.geo.json/master/countries/USA/PR/Añasco.geo.json
$ cp Añasco.geo.json prCounties.txt
$ python
>>> import simplejson
>>> string = file("prCounties.txt","r").read()
>>> d = simplejson.loads(string)
>>> print d
{u'type': u'FeatureCollection', u'properties': {u'kind': u'state', u'state': u'PR'}, u'features': [{u'geometry': {u'type': u'MultiPolygon', u'coordinates': [[[[-67.122, 18.3239], [-67.0508, 18.3075], [-67.0398, 18.291], [-67.0837, 18.2527], [-67.122, 18.2417], [-67.1603, 18.2746], [-67.1877, 18.2691], [-67.2261, 18.2965], [-67.1822, 18.3129], [-67.1275, 18.3184]]]]}, u'type': u'Feature', u'properties': {u'kind': u'county', u'name': u'A\xf1asco', u'state': u'PR'}}]}
看吧,完全没有错误。
在某个地方,你对这些数据做了一些操作,把它变成了其他不是JSON的东西。我猜测,你在做了一堆不必要的decode
和encode
调用之后,还做了simplejson.loads
,然后又试图对返回的dict
的repr
再进行一次simplejson.loads
。或者你可能对一个已经包含编码过的JSON字符串的dict
进行了JSON编码。不管你做了什么,错误的地方在于那段代码,而不是你给我们展示的代码。
最简单的解决办法可能就是一开始就正确生成prCounties.txt
。这不过是70多个文件,每个文件几行内容,可能只需要两行bash命令或者四行Python代码就能完成……