字符集转换Python

时间:2013-11-07 00:21:31

标签: python character-encoding

上下文

我有一些python代码,我用它来使用ffprobe从视频文件中读取元数据。我正在运行ffprobe命令作为子进程,收集stdout(采用JSON格式),然后将其转换为python字典。代码看起来像这样:

query = FFprobeQuery()
stdout, stderr = query.run(video)

这是一个ffprobe命令作为子进程调用。 ffprobe命令是:

ffprobe -print_format json -show_streams "video.mov"

标准输出是:

"streams": [
    {
        "index": 0,
        "codec_name": "h264",
        "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
        "codec_type": "video",
        "codec_time_base": "1/2000000",
        "codec_tag_string": "avc1",
        "codec_tag": "0x31637661",
        "width": 960,
        "height": 540,
        "has_b_frames": 0,
        "pix_fmt": "yuv420p",
        "level": 31,
        "is_avc": "1",
        "nal_length_size": "4",
        "r_frame_rate": "1000000/41667",
        "avg_frame_rate": "55000000/2291667",
        "time_base": "1/1000000",
        "start_time": "0.000000",
        "duration": "2.291667",
        "bit_rate": "2090617",
        "nb_frames": "55",
        "tags": {
            "creation_time": "2013-11-04 09:38:31",
            "language": "eng",
            "handler_name": "Apple ╠µ╔Ý╩²¥¦┤ª└Ý│╠ð‗"
        }
    }
] 

然后我使用json包将上面的字符串(stdout)转换为python字典:

video_data = json.loads(stdout)

错误

上述过程通常可以正常运行,但在这种情况下,UnicodeDecodeError调用会引发json.loads(stdout)。我没有在这里包含整个堆栈跟踪,但错误看起来像这样。

UnicodeDecodeError: 'utf8' codec can't decode byte 0xcc in position 6: invalid continuation byte

重要的是要注意,在这种特殊情况下,视频文件已经从中国发送,因此我猜测stdout字符串中有一些字符导致json.loads(stdout)调用引发的错误。我的猜测是Apple ╠µ╔Ý╩²¥¦┤ª└Ý│╠ð‗的处理程序名称值。

解决方案

我的理论是stdout字符串需要从一些中文编解码器转换为其他编解码器。稍微探讨一下后,我发现以下代码(使用chardet将stdout从GB2312转换为ascii)实际上有效:

import json
import chardet

detection = chardet.detect(stdout)
encoding = detection.get('encoding')
decoded_stdout = stdout.decode(encoding)

video_data = json.loads(decoded_stdout)

问题

我对字符集一无所知,所以我想:

1。确定我是否采取了正确的方法?

2。了解为什么我编写的转换代码确实有效?

3. 确定是否可以使用标准python库解决问题?

非常感谢所有评论。

1 个答案:

答案 0 :(得分:1)

首先,澄清一下:您的方法不会从GB2312转换为ASCII - 您也不希望它,因为ASCII不能代表字符串'╠µ╔Ý╩²¥¦┤ª└Ý│╠ð‗'decode返回的是一系列无法​​在磁盘上直接表示的抽象字符 - 编码是序列化规则。这种类型在Python 2中称为unicode,在Python 3中称为str; {2}中stdout的类型为str,Python 3中为bytes

将原始字节传递到json.loads尝试使用utf-8将输入反序列化(解码)为字符串。这会给出您看到的错误,因为您的输入是使用不同的,不兼容的编码序列化的。首先自己解码是正确的方法 - 在较新版本的Python中,json.loads要求你这样做(它严格要求字符序列而不是字节序列)。

有一点需要注意:猜测编码,chardet的方式, hard ,并且可能容易出错。它碰巧适用于这种特殊情况,但如果您需要对其他文件执行类似操作,则无法保证它能够正常工作。 可能是您可以使用的最佳方法 - 通常,您可能希望在文件的元数据中看到早期提到的编码,但在这种情况下似乎不是这样。但是在尝试猜测之前,你应该总是试着找一些关于它的权威信息。