simplejson:加载西班牙字符 -- utf-8

1 投票
3 回答
4781 浏览
提问于 2025-04-17 17:22

我正在尝试用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 个回答

0

你需要在你的 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)
2

你的输入文件不是有效的JSON格式。在字符串"A\xf1asco"前面有一个u,这是Python的语法,而不是JSON的语法。正确的写法应该是:

"name":"A\xf1asco",

这样写就可以了:

>>> import json
>>> json.loads(u'{"name":"A\xf1asco"}')
{u'name': u'A\xf1asco'}
2

这里有两个问题。首先:

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的东西。我猜测,你在做了一堆不必要的decodeencode调用之后,还做了simplejson.loads,然后又试图对返回的dictrepr再进行一次simplejson.loads。或者你可能对一个已经包含编码过的JSON字符串的dict进行了JSON编码。不管你做了什么,错误的地方在于那段代码,而不是你给我们展示的代码。

最简单的解决办法可能就是一开始就正确生成prCounties.txt。这不过是70多个文件,每个文件几行内容,可能只需要两行bash命令或者四行Python代码就能完成……

撰写回答