如何在Ruby中使用open3为标准输入和输出设置特定编码

3

当通过stdin和stdout发送输入并捕获输出时,是否可以将编码设置为utf-8,以便保留特殊字符(例如™,à等)?

这是我的代码(我正在使用Windows,我认为输出具有此编码:IBM866):

require 'open3'
require 'pragmatic_segmenter' # just a gem that segments paragraphs to sentences

Open3.popen3("tagger") do |stdin, stdout, stderr, wait_thread|
  tokenized_group = Proc.new do |sentences|
    sentences_array = PragmaticSegmenter::Segmenter.new(text: sentences).segment

    sentences_array.map do |sentence|
      stdin.puts "#{sentence}" 
      stdout.gets.gsub(/\n$/,"").encode("utf-8") #=> is it possible to get this utf-8, right now its IBM866?
    end
  end

  puts tokenized_group.call "Some random sentence with ™. Another random sentence with à." 
  #output => Some/DT random/JJ sentence/NN with/IN тДв/NN ./. Another/DT random/JJ sentence/NN with/IN ├а/NN ./.

  stdin.close
end

正如你所看到的,由于编码不同,特殊字符在输出中没有被保留。那么,我该如何在标准输出中恢复这些字符呢?


你为什么相信输出是IBM866编码?stdout.internal_encoding.external_encoding返回什么?sentences_array中的项目编码是什么?返回字符串中所涉及字符的实际字节值是多少? - Jordan Running
@Jordan 当我尝试使用 string.match 时,它会报错 不兼容的编码正则匹配(UTF-8 正则表达式与 IBM866 字符串)(Encoding::CompatibilityError)internal_encoding 返回 nil,external_encoding 返回 IBM866。对于 ™(返回 тДв),其编码为 [209, 130, 208, 148, 208, 178],对于 à(返回 ├а),其编码为 [226, 148, 156, 208, 176] - B A
1个回答

3

这是一个有点奇怪的问题。我认为以下方法可以解决:

stdout.gets.encode(Encoding::IBM866, Encoding::UTF_8)

这告诉encode源编码和目标编码。需要注意的是,在调用gsub或任何其他正则表达式方法之前,您需要这样做。

您可以通过使用set_encoding来告诉stdout对象为您进行转换,从而跳过此步骤:

stdout.set_encoding(Encoding::IBM866, Encoding::UTF_8)

在你的popen3块中,首先要做的是这个。

顺便说一下,这是我用来测试的代码:

# ™(returns тДв)
a = [209, 130, 208, 148, 208, 178] 

# à(returns ├а)
b = [226, 148, 156, 208, 176]

a_str = a.pack("c*")
puts a_str.encode(Encoding::IBM866, Encoding::UTF_8)
# => ™

b_str = b.pack("c*")
puts b_str.encode(Encoding::IBM866, Encoding::UTF_8)
# => à

刚试了一下,第一个出现了U+00E9 from UTF-8 to IBM866 (Encoding::UndefinedConversionError)的错误。第二个(即在打开块开始处设置正确的编码)没有报错,但是输出了相同的错误字符。 - B A

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接