【问题标题】:How to write BOM marker to a file in Ruby如何在 Ruby 中将 BOM 标记写入文件
【发布时间】:2012-04-10 19:36:43
【问题描述】:

我有一些带有拐杖的工作代码,可以将 BOM 标记添加到新文件中。

  #writing
  File.open name, 'w', 0644 do |file|
    file.write "\uFEFF"
    file.write @data
  end

  #reading
  File.open name, 'r:bom|utf-8' do |file|
    file.read
  end

有什么方法可以自动添加标记而不在数据前写神秘的"\uFEFF"?可能是File.open name, 'w:bom' # this mode has no effect 之类的?

【问题讨论】:

  • 请不要使用 UTF-8 的 BOM !!! Unicode 联盟既不要求也不推荐
  • 谢谢大师指导。我采用不同的方法来解决问题,并修补了我的模板引擎以尊重 Encoding.default_external。
  • “不,无论 Unicode 文本如何转换:UTF-16、UTF-8 或 UTF-32,BOM 都可以用作签名。” unicode.org/faq/utf_bom.html
  • 除非您在 Windows 世界中并且他们让您将 BOM 应用于 ascii 文件以被识别为 UTF-8
  • @tchrist 实际上,在某些情况下,Unicode 联盟推荐了 BOM。见unicode.org/faq/utf_bom.html#bom10 情况有: 1. 符合一定的协议(如微软.txt文件); 2. 在允许的协议中指定文本流的编码或字节顺序,否则会不清楚。

标签: ruby utf-8 byte-order-mark


【解决方案1】:

唉,我认为您的手动方法是可行的方法,至少我不知道更好的方法:

http://blog.grayproductions.net/articles/miscellaneous_m17n_details

引用 JEG2 的文章:

Ruby 1.9 不会自动将 BOM 添加到您的数据中,因此您需要 如果你想要一个,需要照顾它。幸运的是,它不是太 艰难的。基本思想只是打印所需的字节 文件的开头。

【讨论】:

  • 您不想在 UTF-8 文件中使用 BOM!
  • 您能解释一下为什么我们不想这样做吗? :) @tchrist
  • @fab 因为 utf8 没有必要。对于 utf16,bom 指示文件是大端还是小端,一个有一个 bom,另一个有一个 bom,bom 是强制性的,但是 utf8 没有两个变体 bom,bom 是不必要的 @987654322 @
【解决方案2】:

**** 这个答案导致了一个新的宝石:file_with_bom ****

我过去也遇到过类似的问题,我扩展了File.open 并为w-mode 添加了额外的编码变体:

class File
  BOM_LIST_hex = {
      Encoding::UTF_8      => "\xEF\xBB\xBF", #"\uEFBBBF"
      Encoding::UTF_16BE => "\xFE\xFF", #"\uFEFF",
      Encoding::UTF_16LE => "\xFF\xFE",
      Encoding::UTF_32BE => "\x00\x00\xFE\xFF",
      Encoding::UTF_32LE => "\xFE\xFF\x00\x00",
    }
  BOM_LIST_hex.freeze
  def utf_bom_hex(encoding = external_encoding)
    BOM_LIST_hex[encoding]
  end

class << self
  alias :open_old :open
  def open(filename, mode_string = 'r', options = {}, &block)
    #check for bom-flag in mode_string
    options[:bom] = true if mode_string.sub!(/-bom/i,'')

    f = open_old(filename, mode_string, options)
    if options[:bom]
      case mode_string
        #r|bom already standard since 1.9.2
        when /\Ar/   #read mode -> remove BOM
          #remove BOM
          bom = f.read(f.utf_bom_hex.bytesize) 
          #check, if it was really a bom
          if bom != f.utf_bom_hex.force_encoding(bom.encoding)
            f.rewind  #return to position 0 if BOM was no BOM
          end
        when /\Aw/  #write mode -> attach BOM
          f = open_old(filename, mode_string, options)
          f << f.utf_bom_hex.force_encoding(f.external_encoding)
        end #mode_string
    end

    if block_given?
      yield f 
      f.close
    end
  end
  end
end #File

测试代码:

EXAMPLE_TEXT = 'some content öäü'
File.open("file_utf16le.txt", "w:utf-16le|bom"){|f| f << EXAMPLE_TEXT }
File.open("file_utf16le.txt", "r:utf-16le|bom:utf-8"){|f| p f.read }
File.open("file_utf16le.txt", "r:utf-16le:utf-8",  :bom => true ){|f| p f.read }
File.open("file_utf16le.txt", "r:utf-16le:utf-8"){|f| p f.read }

File.open("file_utf8.txt", "w:utf-8", :bom => true ){|f| f << EXAMPLE_TEXT }
File.open("file_utf8.txt", "r:utf-8", :bom => true ){|f| p f.read }
File.open("file_utf8.txt", "r:utf-8|bom",              ){|f| p f.read }
File.open("file_utf8.txt", "r:utf-8",                     ){|f| p f.read }

一些备注:

  • 代码来自 1.9 之前的版本(但仍然有效)。
  • 我使用-bom 作为bom 指示器(ruby 1.9 使用|bom

一些需要修复才能变得更好:

  • 使用|bom 代替-bom
  • 使用标准r|bom进行阅读
  • 启用 ruby​​ 1.8 和 1.9

也许我明天会找时间重构我的代码并将其作为 gem 提供。

【讨论】:

  • 感谢您的建议,但对于我的项目而言,这将是矫枉过正。
  • 宝石 +1。我想你可以联系 Ruby 或 Rubinius 的人,将其合并到官方发行版中。
  • @AleksanderPohl 宝石已发布rubygems.org/gems/file_with_bom 我希望我没有疏忽。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-16
  • 2023-03-26
  • 2013-04-01
  • 1970-01-01
  • 2011-01-27
  • 1970-01-01
相关资源
最近更新 更多