Ruby 问一个关于编码的问题

adventurelw · 2012年04月19日 · 最后由 adventurelw 回复于 2013年03月27日 · 3738 次阅读

使用 csv 模块读取 csv 格式的 utf-8 文本,类似于这样的: xiaoli,小李,经理,男 xiaowang,小王,助理,女 data=CSV.read('data.txt') 读取 而后将其转成 people[:xiaoli] 形式的 hash 表,奇怪的事情发生了: 转的时候用的是 data[0][0].to_sym 作为 hash 的符号索引,读取的时候直接输入 people['xiaoli'.to_sym] 的时候发生如下错误: in get_name': undefined method[]' for nil:NilClass (NoMethodError) 意味着'xiaoli'.to_sym 不等于 data[0][0].to_sym,直接测试 'xiaoli'.to_sym == data[0][0].to_sym 输出 false。。。。。。 从 data 中再读取使用 people[data[0][0].to_sym] 没有问题 此问题只在 windows 中发生,最诡异的是,只有第一行数据会发生这个错误,以后的数据都不会。如果将其他行的数据 copy 到第一行,那么新 copy 到第一行的数据发生这个错误,旧的第一行错误消失。。。。。。 直接新建文档手工写入数据保存成 utf-8 文件错误同样。 真是愁坏了,不知道有没有谁遇到过的?请多多指教,万分感谢。

csv 第一行有特殊意义的啊,google 下先

哦,我以为是 BOM header 问题呢

是么,那可能是前面搜索时描述问题没有看到相关的东西,再查查。。。

不过 ubuntu 下没问题啊。。。。。。刚记起来。

这种情况,何不输出 data[0]data[0][0] 看看到底是什么?是否是 nil,是的话再检查为何会是 nil。

data[0][0] 输出是'xiaoli',但诡异就是这玩意和直接输入的'xiaoli'不一样——用 encoding 查编码是一样的,都是 utf-8。。 将 puts data[0][0] 的结果 copy 到 people[:] 冒号的后边就没问题。。。。。。直接输入的:xiaoli 就显示 nil 错误。。。。

还有一个比较搞的现象,在 windows eclipse 下 通常:xiaoli 这种符号显示为蓝色,稍微有点斜体。 但 copy puts data[0][0] 到 people[] 的方括号中在前面加冒号后会导致所有的符号变成普通代码的颜色黑色和普通代码的正规字体,输出正常内容;不删除冒号只删除 xiaoli 然后再输入小李不会出现变化,将整个符号全部删除重新输入:xiaoli 则会导致所有符号变成蓝色和斜体,输出 nil……实在是对这个非常无语。 puts works[:xiaoli].inspect puts works[:xiaocai].inspect puts 'xiaoli' == 'xiaoli' puts 'xiaoli'.encoding puts 'xiaoli'.encoding 上面代码第三行输出 false,后两行都输出 utf-8 另外,搜索了一下发现 csv 文件第一行可以为列名,但这不是必要的,而且应该也不影响对内容包括列名本身的读取才对;其余的就不知道第一行还会有什么玄机了?

问题终于搞清楚了,windows 下的 utf-8 或者 unicode 文件的开头都会有字符串'\xef\xbb\xbf'标志 ‘\xef\xbb\xbfxiaoli’ 虽然和'xiaoli'在 utf-8 格式下显示都是'xiaoli',但还是不一样。 现在的问题是:ruby 下字符串是不会显示那个标志的,用 start_with?也判断不出来有这个标志,所以也没有办法去掉……不知道该怎么办。

  1. 换个不写 BOM 的 CSV 的编辑器
  2. 自己读取行,对包含 BOM 的行 strip,然后用 CSV.parse 解析行
匿名 #10 · 2012年04月21日

's.force_encoding("ascii")[3,s.length - 1].force_encoding("utf-8")' 你用的应该是 1.9 吧,这样就把前三个字节去掉了。1.8 的话直接去掉前三个就行

匿名 #11 · 2012年04月21日

s.force_encoding("ascii")[3,s.length - 1].force_encoding("utf-8") 单行代码好隐晦。。

那个 \xEF\xBB\xBF 就是 Unicode 的 BOM ,是给软体判断该文件要以 big endian 还是 little endian 读取。

不过实务上 UTF-8 并不需要 BOM,因为它编码的时候就是以 byte 为单位,在不同的机器之间也只会有一种 byte order 。

另参考 Joel on Software 的这篇: http://local.joelonsoftware.com/wiki/The_Joel_on_Software_Translation_Project:%E8%90%AC%E5%9C%8B%E7%A2%BC

@lululau 复制在 ubuntu 系统下的文件到 windows 下就没有这个 BOM 问题了,不过 strip 去不掉那个标志好像 @jjym 这个可以,只要判断第一行就没问题。

多谢所有老大的回答!

想问下 win7 用 eclipse3.7 为什么装不上 RDT?

#14 楼 @leohu Help->Install New Software-> http://download.eclipse.org/releases/indigo 里面有个 Programming Languages 直接就有 ruby 开发工具啊,直接选上安装就可以了。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册