python过滤引起xml报错的非utf8字符

       很久以前只有ascci这个东西,他是单字节的,我们知道一个字节 是0x00-0xff,所以assci中 0x00-1f 是控制符,0x20-0x7e 是可显示字符 ,0x7f 是删除,至于0x7f以上的 貌似没啥用,这些字符一般都会造成乱码,而且在我们日常的网页,xml,等普通文本中,0x0-01f 一般也都是乱码,只有0x09 0x0a 0x0d 代表 \t \n \r 可以使用,所以如果从word中复制的文字到网页中,一些不在0x20-0x7e之间的字符很容造成乱码,或者造成标签不闭合都奇怪的情况,说白了,assci这一套只能满足用英文的国家,其他国家的怎么办,所以他们商量出了一个unicode。

       unicode它是一种全球通用字符的编码方式,每个字符两个字节,三个字节甚至四个字节,基本上地球上所有的字符都可以用unicode来表示,

但是如果如果用unicode来存储字符,根本无法解析,因为你根本不知道该读一个字符还是两个还是三个,如果统一用四个,那么会造成很大的浪费纯英文的国家肯定不高兴了,这破玩意对我们没啥好处,结果让我们的内容大小翻一倍,于是他们就推出了utf8。utf8是unicode的一种实现,它定义了一套规则,不但可以最小化的存储字符,而且还可以方便字符的读取

       utf8的编码格式是,第一个字节的第一位如果是0,那么这个字符就是一个单字节字符,它表示的字符和assci相同

比如

0b01000001 

第一个是0,代表这个就是一个字符A

如果不是0,从左边数,有几个1,那么这个字符就用几位来表示

比如

0b11xxxxxx这个就是代表从我开始的两个字节代表一个字符

0b111xxxxx这个代表三个字节是一个字符

有的同学问了,0b10xxxxxx 呢,代表一位?错啦,自己本身就占了一位,而且一位的字符是0开头的。那就是10 没啥用?

当然不是,utf8又有规定,多字节的第二位以及以后的字节统一 10 打头,这样utf8的编码就一目了然了吧?0开头的是单字节,10开头的是多字节的普通位,11开头的是多字节的打头位,所以,0xxxxxx 后边肯定不会出现 10xxxxxx , 11xxxxxx后边肯定不会有0xxxxxxx , 11xxxxxx后边肯定有10xxxxxxx,明白了嘛?

又有大国不高兴了,utf8的话汉字全都是三个字节了嘛?不高兴,所以就有了gb(gbk,gb2312 ,gb18030)系列,统一两个字节

但是现在全球化的发展,gb肯定也搞不定啊,而且现在硬盘也不值钱,算了,算了,大家还是utf8吧。

 

       但是为什么python里用unicode呢,其实python里的unicode表示方法并不是一个字符串,而是一个对象,或者是list,list的中每一项都是一个整数用来代表一个unicode编码,如果你用type的话,得到的是个<unicode>而不是str

比如 u"123中国"

那么uncode数组就变成  [0x31,0x32,0x33,\u4e2d,\u56fd]

这样也不会造成字节的浪费,读取也容易,而且方便编码成其他的编码

其他的任意编码对于python来讲,都是针对一个字符串的,但是unicode,它是一个特殊的对象,它并不是一个str,也是因为unicode是万码之源。

有同学问了,知道这些有啥卵用,我不知道每天还是活的很开心

楼主就和大家讲讲最近遇到的一个bug

 

因为要给第三方同步数据,这些数据由我们的用户编写提交,第三方比较古老,采用xml这种格式,某天客户叫了,说有一部分数据全部解析错误,

我用浏览器打开那个xml,发下报错,不是utf8字符,一开始咱也不懂,也不敢问,肉眼看起来没啥问题的字符咋就报错了呢,

咱就用了个笨办法,先删掉一半,再删掉一半,发现某个位置由一个肉眼很难发现的空格,找个16进制的编辑器一看,是个字符叫0x1f,所以第一次,好办,咱过滤掉,replace("0x1f","")

过了几天,客户又叫了,还是老问题,咱在用老办法,发现是一个0x0f,过了几天又来了一个0x1a,0x03

坑爹呐,

所以我们就给来个统一过滤吧,思路很简单,遍历unicode字符,如果是单字节 ord() 小于 0xff的,都是单字节,如果不在0x20-0x7e内 全部换成空值,当然啦,0x09 0x0a 0x0d ( \t \r \n )这三剑客 咱不能过滤

代码如下


def unicode_filter(src):
    '''过滤unicode中一些在xml会报错的字符 常见字符 [0,31],[127,255]'''

    src_list = list(src)
    for i in range(len(src_list)):
        c = src_list[i]
        code = ord(c)
        if code <= 0xff:  # 单字节
            # 删除一个非显示字符 0-31 和 127 ,其中 \t \t \n 留下

            if code <= 31:  # 控制字符
                # 留下换行,\t 字符
                if code not in [0x09, 0x0a, 0x0d]:
                    src_list[i] = u''

            if code > 126:  # 非assci
                src_list[i] = u''

过滤完之后,再编码成utf8写进xml文件,简直完美 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值