分享

Ruby实例编程说明字符编码,解决乱码问题

 昵称11935121 2018-07-21

Ruby实例编程说明字符编码,解决乱码问题

日常编码中,你是不是常见到乱码问题,那么乱码是怎么来的呢,今天虫虫就以Ruby为例来,说明字符编码、底层的字节码以及各种字符编码转化,最后说下怎么解决乱码问题。

我们以一个Ruby抛出的错误异常为开头,某年某月某日,你正用irb学习Ruby突然屏幕上抛出了一个异常:

Encoding::InvalidByteSequenceError: '\xFE' on UTF-8

或者 'they're'被显示为'they’re'。

所以,当出现编码错误,或者乱码时候,我们怎么排查问题出在哪里?如何解决它?

什么是编码?

如果你了解字符串以及编码之间的关系,其实这些问题很容易解决。

我们可以将字符串视为字节数组或数字:

2.1.4 :002 > 'chongchong!'.bytes

=> [99, 104, 111, 110, 103, 99, 104, 111, 110, 103, 33]

Ruby实例编程说明字符编码,解决乱码问题

在这种编码中,99表示c,104表示h,…,33表示!。

当你使用英语中不常见的字符时,情况会变得更加复杂:

2.1.4 :007 > 'chongchong'.bytes

=> [240, 159, 166, 139, 99, 104, 111, 110, 103, 99, 104, 111, 110, 103]

Ruby实例编程说明字符编码,解决乱码问题

现在很难判断哪个数字代表哪个字符了把。这个蝴蝶字符使用一组字节[240, 159, 166, 139]表示,而不是一个字节。但字节和符号之间会存在着一定的对应关系。这种定义字节和符号(字符串)之间的对应关系,我们叫编码。

不同编码转换

在不同编码环境下,一个字节可能呈现出不同的符号表现:

2.1.4 :021 > str = '虫虫,秊﨟蘒!'.encode('GBK');

2.1.4 :022 > str.encode('UTF-8')

=> '虫虫,秊﨟蘒!'

Ruby实例编程说明字符编码,解决乱码问题

2.1.4 :027 > str.bytes

=> [179, 230, 179, 230, 163, 172, 253, 158, 254, 72, 254, 73, 33]

Ruby实例编程说明字符编码,解决乱码问题

GBK的字串,我们看看在西文编码的ISO-8859-5下会是怎么显示呢?

str.force_encoding('ISO-8859-5'); str.encode('UTF-8')

2.1.4 :003 > str.force_encoding('ISO-8859-5'); str.encode('UTF-8')

=> 'ГцГцЃЌ§\u009EўHўI!'

Ruby实例编程说明字符编码,解决乱码问题

2.1.4 :004 > str.bytes

=> [179, 230, 179, 230, 163, 172, 253, 158, 254, 72, 254, 73, 33]

Ruby实例编程说明字符编码,解决乱码问题

我们可以看到,字节码没有变化,但是看起来乱码了。改变编码会改变字符的显示方式,但是不会改变字节码,不同的编码,有不同的字节码解析方式。

从GB2312到GBK,选择UTF8

另外我们需要注意的是,每一种编码的数量都有限量,有些编码数量少,会导致其他编码转过来会不支持,比如GBK是GB2312的扩展集合支持21886个字符,而GB2312只支持7445个字符。注意UTF8和UTF16是全字符集,支持所有编码的字符,这就是为什么建议大家写代码一定都用UTF8的原因,当然在Windows下微软屎一样的,坚持自己要带UTF8 BOM,还不能方便的转换,所以也很讨厌。

2.1.4 :005 > str.force_encoding('GB2312'); str.encode('UTF-8')

Encoding::InvalidByteSequenceError: '\xFD' followed by '\x9E' on GB2312

from (irb):5:in `encode'

from (irb):5

from /home/lz/.rvm/rubies/ruby-2.1.4/bin/irb:11:in `

'

Ruby实例编程说明字符编码,解决乱码问题

后面那三个字,在GB2312下没有编码,所以报错了。

Ruby实例编程说明字符编码,解决乱码问题

我们将编码修改为GB18030,这是一种比GBK更大的中文字符集,显示就没问题了。

我们也可以给encode函数添加invalid和undef两个参数,这样当无法解释时候会用默认的?来代替,就不会报错了。

'chongchong,秊﨟蘒!'.encode('GB2312', invalid: :replace, undef: : replace)

=> 'chongchong\x{A3AC}???!'

Ruby实例编程说明字符编码,解决乱码问题

我们常见的编码问题有两种现象,一种是编码不对,就是完全乱码,乱显示随机字符,还有一种就编码不足以解析字符集会有很多的??的。

Ruby实例编程说明字符编码,解决乱码问题

当你对字符转换编码时,很多时候,你不能获得足够的信息,你不知道究竟是哪一个被替换成了?但是你起码知道选的编码没有错,只不过不足以显示所有字符而已,你换一种字符集更多的编码就正常了。比如GB2312->GBK->GB18030

总结

在文章中,我们目前用到了三个字符串对象方法来帮我们处理编码问题:

ecode,将字符串转换为另一种编码(在新编码中将字符转换为相应字符)

bytes,它将显示组成字符串的字节码(整数数组)

force_encoding,强制将一种编码转换为一种编码,用这宗编码来重新解析内容。

其实上编码问题在各种语言都存在,这儿虫虫选择了Ruby中三个类方法来作为实例演示,其他语言中也有类似的方法和函数,比如:

golang中的golang.org/x/text/encoding/simplifiedchinese包。

python中的enode()和decode(),XX_name(XX为编码)方法。

Perl中encode包中也有enode()和decode()。

Java中有getBytes(),charset类有enode()和decode()方法。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多