我正在尝试使用 python2.7 对使用 twitter API 获得的 json 文件按国家/地区进行情绪分析。我的问题是,尽管按照各个论坛的建议分配了默认编码,并且还对文本进行了编码,但我无法“翻译”“稀有”字符。我分配默认编码:
#!/usr/bin/env
# -*- coding: UTF-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
在为 'place' 变量赋值时,如果我不强制进行任何编码更改,它会向我显示生成的国家名称中的奇怪字符:
try:
jsonLine = json.loads(line)
place = jsonLine["place"].get('country')
text = jsonLine["text"]
score = self.tweet_Score(text, weights)
yield (place, score)
except:
pass
结果示例:
“墨西哥” 217.41 “萨尔瓦多” 7.78 “阿拉伯联合酋长国” 0 “西班牙” 300.62
相反,如果我在使用 .decode('utf-8').encode('utf-8') 将值分配给“place”期间进行解码:
try:
jsonLine = json.loads(line)
place = jsonLine["place"].get('country').decode('utf-8').encode('utf-8')
text = jsonLine["text"]
score = self.tweet_Score(text, weights)
yield (place, score)
except:
pass
使用最后一种情况,带有奇怪字符的记录会从我的结果中消失,并停止对他们计算的值进行评分(这是不正确的)。我尝试了解码和编码的不同组合,但行为如所述。
我考虑过做一些replace
调整最常见的情况的选项,但这不合适,因为我分析评分的文本内容有同样的问题,其中有很多情况,所以我想编码必须有一些解决方案,但我不知道还能尝试什么。
提前感谢您的帮助!
附:为了提供更多信息,这是我在示例中使用的国家/地区字段的样子,它取自我的实际输入文件:
javascript(和 JSON)中的 \u 序列
那些“奇怪的字符”不是错误。它们是 JSON 决定以不依赖于 encoding的方式表示非 ascii 字符的方式。
让我以案例为例进行说明
"España"
。该字符"ñ"
不是 ASCII 的一部分,因此在 JSON 字符串中输入它时,我们有两个选项:"ñ"
。这种编码通常是 UTF-8,因此是 Unicode。在 Unicode"ñ"
中它有代码 U+00F1,但是在以字节为基本单位的 UTF-8 编码时,它将占用两个字节的值 C3 和 B1(十六进制)。读取此字符串的人必须知道选择的编码是 UTF-8,以便将这两个字节“收集”回单个字符 (U+00F1),从而获得"ñ"
. 如果您改为假设像 latin1 这样的编码,其中每个字节都是一个字符,它会错误地将其解码为两个字符:"ñ"
\
。此字符用于多种用途,以便能够将字符放入字符串中,否则这些字符将不可见或引起混淆。最典型的情况是\n
换行符,但我们也有\r
回车、\b
“哔”、\t
制表符等......还有一个与我们有关的,\u
一个 unicode 字符。后面必须跟四个对相关字符进行编码的十六进制数字。因此,在我们的例子中,六个字符的序列:\u00f1
只代表一个:eñe。第二种情况更可取,因为您没有使用任何编码来存储 Unicode 字符,而只是用另一个 ASCII 序列来表示它。就像您输入的 HTML 一样
ñ
,它也是浏览器将显示为的 ASCII 序列ñ
。因此,JSON 文本包含的事实
"Espa\u00f1a"
不是问题。包含正确的字符串。如果 JavaScript 程序尝试显示它,则 eñe 将正确显示,如您在此处看到的:python2中的\u序列
python2的这个序列没有特殊含义。如果在 python 中一个字符串包含
\u00f1
,它将按原样显示为六个文字字符:但如果它是一个unicode 字符串(
u
开头引号前面有一个),那么它会被识别和处理:虽然 python 中最常见的形式不是
\u00f1
but\xf1
,这也是公认的:但请注意,这两种形式中的任何一种都将表示 ñ 的 Unicode 字符保存在字符串中,而不是字符序列
\u00f1
或\xf1
. 这些序列被处理并转换为相应的字符。如果我们想保存那些特定的序列,我们将不得不\
用另一个转义\
,以防止它被处理(这将保存一个\
)到链中。所以:只放一个或放两个的区别在于
\
,在第二种情况下,生成的文本不再包含任何 eñe,而只是一个 ASCII 序列(其中字符\
、u
等0
是其中的一部分)。如果您查看这些字符串的长度,最好理解这一点:json和python
最后,我们进入了它的核心。我们在 JSON 中有一个字符串,其中包含
\u00f1
我们已经看到的 JSON 中的合法字符,我们想在 python 中读取它。例如,我们从文件(或从套接字,没关系)中读取了我们存储在 中的字符串,line
如下所示:在 python 2 中,从文件(或从套接字)读取会产生 a
str
,它是一个字节字符串,而不是 Unicode 字符串。我们可以尝试将其转换为 Unicode,为此我们通常必须知道从中读取它的文件的编码。但是在这种情况下,由于上述原因,编码是无关紧要的,因为它已被选择将 eñe 表示为 ASCII 序列\uXXXX
。因此,以下内容应该可以正常工作:如您所见,没有错误,但似乎也没有工作。实际上它确实有效(显示的字符串不再是 type
str
而是 typeunicode
),但是字符\u00f1
没有按预期显示。这是因为我们所拥有的相当于
\\u
在 Python 中输入的文本,因为我们所拥有的字符串实际上是\
一个字符而不是 unicode 字符。最后一部分可能很难理解,但这并不重要,因为您在收到 JSON 字符串后要做的第一件事就是使用解码它,
json.loads()
并且此方法已经负责检测字符串\u
并将其转换为相应的蟒蛇字符:因此它有效。
为什么你认为它对你不起作用?
也许您不是打印字符串(如上面的示例),而是打印数据结构,例如
jsonLine
结果变量。如果你这样做,你显然会看到奇怪的事情:这是因为当您打印字典或列表时,Python 会向您显示组成它的数据的表示形式。例如,在这里我们可以看到键和值都是 Unicode 字符串(它们
u
在引号前有一个)。在这些字符串中,非 ascii 字符以它们的“python 表示”(\xf1
)显示。但这只是它的显示方式。在内部\xf1
,它是一个ñ
Unicode,因此只要您想打印该字符串,它就会显示出来。也可能不是从 python 打印字符串,而是将结果转换回 JSON。在这种情况下,编码器会将每个非 ASCII 字符
json.dumps()
重新编码\uXXXX
为标准 JSON 格式,即:但这里再次没有错误。这是正确的行为。这样生成的 JSON 是纯 ASCII,它不依赖于编码,当 JavaScript 客户端使用它并尝试显示它时,它会正确显示
"España"
,请参阅: