ruby:为什么 utf-8 中的 File.read 无法读取有效的 utf-8 字符?

ruby: How comes File.read in utf-8 fails to read a valid utf-8 character?

提问人:rellampec 提问时间:5/10/2022 最后编辑:rellampec 更新时间:5/10/2022 访问量:172

问:

上下文

  • 尝试使用编码的文件进行解析ruby 2.6.3+csvutf-8
  • 该文件包含一个引发 CSV::MalformedCSVError 的字符
  • 隔离后,感兴趣的字符似乎是单个 LOW-9 引号 ()。这个。U+201A
  • 该字符似乎由 (3 个字节,十六进制:或) (ref1ref2UTF-8e2809a\xe2\x80\x9a)

test.csv文件内容

"value"
"abc‚d"

使用类解析时出错:CSV

irb(main):001:0> require 'csv'
=> true
irb(main):002:0> CSV.read("test.csv", **{headers: true, skip_blanks: true, encoding: "utf-8"})
Traceback (most recent call last):
        2: from C:/ruby/Ruby26-x64/lib/ruby/2.6.0/csv/parser.rb:297:in `parse'
        1: from C:/ruby/Ruby26-x64/lib/ruby/2.6.0/csv/parser.rb:711:in `build_scanner'
CSV::MalformedCSVError (Invalid byte sequence in UTF-8 in line 2.)

虽然是受支持的字符:\u201autf-8

irb(main):001:0> str = "\u201a"
=> "‚"
irb(main):002:0> str.ord.to_s(16)
=> "201a"
irb(main):003:0> str.encoding.name
=> "UTF-8"
irb(main):004:0> str.unpack("H*")
=> ["e2809a"]

处理编码错误scrub

String#scrub 与 a 一起使用似乎没有得到 SINGLE LOW-9 QUOTATION MARK。请参阅下面的代码(参考原始代码):blockx82

irb(main):001:0> content = File.read('test.csv', encoding: 'utf-8')
=> "\"value\"\n\"abc\x82d\"\n"
irb(main):002:0> content.scrub! do |bytes|
irb(main):003:1*   "<" + bytes.unpack('H*')[0] + ">"
irb(main):004:1> end
=> "\"value\"\n\"abc<82>d\"\n"
irb(main):005:0> require 'csv'
=> true
irb(main):006:0> CSV.parse(content, **{headers: true, skip_blanks: true, encoding: "utf-8"}).each do |row|
irb(main):007:1*   pp row["value"]
irb(main):008:1> end
"abc<82>d"
=> #<CSV::Table mode:col_or_row row_count:2>

如上所示,SINGLE LOW-9 引号替换为 ,这是违规字节的十六进制表示形式。在这一点上,我有点迷茫。<82>

问题

虽然似乎一致地有一个 和 无法找到 UTF-8 字符的 3 个字节(而是获取一个字节:):CSV::MalformatedCSVErrorString#scrube2809a0x82

  1. 如果字符受 (as ) 支持,则错误的根本原因是什么?\u201aUTF-8e2809a
    • 在文本编辑器 (Notepad++) 中打开文件,字符将正确显示在文本区域上。当我在此 Unicode 查找中复制并粘贴字符 () 时,它会正确识别该字符。所以它似乎没有什么问题。csv
  2. 查看上面的代码示例 (),和 的用法似乎没有问题。您能否确认(解释)或丢弃错误是否与这些方法的使用有关?irbCSV.readFile.read

也许没有什么可以修复的,不是意料之中的,但我不确定。如果不是不可能的话,创建一个通用的解决方案来正确发现违规字符似乎相当困难。ruby

Ruby UTF-8 字符编码

评论

0赞 JosefZ 5/11/2022
Notepad++ 通知状态栏中的文件编码
0赞 rellampec 5/11/2022
@JosefZ是的:。不过,发现得很好。我会更新这个问题。看起来里面显示的角色不是本来的样子。有一个变音符号字符。一旦我得到更多信息,我将更新问题。希望这能带来一些问题。UTF-8Notepad++
0赞 Stefan 5/12/2022
你能显示文件的字节值吗?(十进制或十六进制)

答: 暂无答案