当编码全部消失时,如何使用Ruby替换VC++资源文件中的文本?

Ant*_*ean 5 ruby windows encoding utf-16

我在解决方案中有一个简单的托管VC++项目.它有一个资源文件,app.rc用于存储程序集信息(版本,产品,版权等).如果我在文本编辑器中打开文件,它会说它是Unicode(UTF-16 LE BOM).如果我选择Unicode - Codepage 1200,Visual Studio只能正确显示它.

VS_VERSION_INFO VERSIONINFO
 FILEVERSION 0,0,0,0
 PRODUCTVERSION 0,0,0,0
 FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
 FILEFLAGS 0x1L
#else
 FILEFLAGS 0x0L
#endif
 FILEOS 0x40004L
 FILETYPE 0x2L
 FILESUBTYPE 0x0L
BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "040904b0"
        BEGIN
            VALUE "CompanyName", "My Company, LLC"
            VALUE "FileVersion", "0.0.0.0"
            VALUE "InternalName", "myassembly.dll"
            VALUE "LegalCopyright", "Copyright (C) 2011 My Company, LLC"
            VALUE "OriginalFilename", "myassembly.dll"
            VALUE "ProductName", "The Product"
            VALUE "ProductVersion", "0.0.0.0"
        END
    END
    BLOCK "VarFileInfo"
    BEGIN
        VALUE "Translation", 0x409, 1200
    END
END
Run Code Online (Sandbox Code Playgroud)

我正在使用Ruby/Rake来配置和运行本地构建.该构建的一部分是替换程序集资源中的版本.我会在文件中读取gsub版本号,并将文件写回.但是,当我读入文件时,我得到了垃圾

irb(main):001:0> File.open("source\\myproject\\app.rc").read
=> "\xFF\xFE/\x00/\x00 \x00M\x00i\x00c\x00r\x00o\x00s\x00o\x00f\x00t\x00 \x00V\x00i\x00s\x
00u\x00a\x00l\x00 \x00C\x00+\x00+\x00 \x00g\x00e\x00n\x00e\x00r\x00a\x00t\x00e\x00d\x00 \x
00r\x00e\x00s\x00o\x00u\x00r\x00c\x00e\x00 \x00s\x00c\x00r\x00i\x00p\x00t\x00.\x00\n\x00\n
\x00/\x00/\x00\n\x00\n\x00#\x00i\x00n\x00c\x00l\x00u\x00d\x00e\x00 \x00\"\x00r\x00e\x00s\x
Run Code Online (Sandbox Code Playgroud)

Ruby认为它是IBM437编码.

irb(main):006:0> File.open("source\\myproject\\app.rc").external_encoding
=> #<Encoding:IBM437>
Run Code Online (Sandbox Code Playgroud)

如果我把内容写到另一个文件,我得到一些奇怪的编码(我的文本编辑器发誓它的Unicode(UTF-16 BE BOM)).

????????????????????????????????????????????????
????
???????????????????????
??
Run Code Online (Sandbox Code Playgroud)

我该如何正确打开/读取此文件?


好的,所以如果我提供正确的编码,我现在可以正确读取文件.

irb(main):003:0> File.open("source\\myproject\\app.rc", "rb:UTF-16LE")
=> #<File:source\myproject\app.rc>
Run Code Online (Sandbox Code Playgroud)

但是,我还不能替换版本字符串.

irb(main):003:0> c = File.open("source\\myproject\\app.rc", "rb:UTF-16LE").read
irb(main):007:0> c.gsub("0.0.0.0", "0.0.5.0")
Encoding::CompatibilityError: incompatible encoding regexp match (US-ASCII regexp with UTF-16LE string)
Run Code Online (Sandbox Code Playgroud)

但是,我无法提供编码gsub.我是否还需要对模式和替换字符串进行编码?

Ant*_*ean 5

读写文件

所以,我尝试的第一件事是寻找如何在Ruby中读/写UTF-16LE文件.我发现了这个问题和答案,建议始终在Windows上以文本文件模式(t)打开文件.

处理文本文件时,应始终传递t修饰符.它对大多数操作系统没有任何影响(不幸的是,大多数Rubyist忘记传递它的原因),但它在Windows上是至关重要的,这就是你似乎正在使用的东西.

所以,我做到了

irb(main):002:0> File.open("source\\myproject\\app.rc", "rt:UTF-16LE")
ArgumentError: ASCII incompatible encoding needs binmode
Run Code Online (Sandbox Code Playgroud)

我不知道是什么binmode,但它可能与二进制文件模式(b)有关.所以,让我们试试吧.

irb(main):003:0> File.open("source\\myproject\\app.rc", "rb:UTF-16LE")
=> #<File:source\myproject\app.rc>
Run Code Online (Sandbox Code Playgroud)

找到了!但是,我仍然看到一些疯狂的控制字符和其他unprintables(\n).

\r\n//\r\n\r\nVS_VERSION_INFO VERSIONINFO\r\n FILEVERSION 0,0,0,0\r\n PRODUCTVERSION 0,0,0
,0\r\n FILEFLAGSMASK 0x3fL\r\n#ifdef _DEBUG\r\n FILEFLAGS 0x1L\r\n#else\r\n FILEFLAGS 0x0L
\r\n#endif\r\n FILEOS 0x40004L\r\n FILETYPE 0x2L\r\n FILESUBTYPE 0x0L\r\nBEGIN\r\n    BLOC
K \"StringFileInfo\"\r\n    BEGIN\r\n        BLOCK \"040904b0\"\r\n        BEGIN\r\n
Run Code Online (Sandbox Code Playgroud)

替换字符串

所以,你会注意到做这样的简单gsub会产生编码错误.

irb(main):004:0> c.gsub("0.0.0.0","0.0.5.0")
Encoding::CompatibilityError: incompatible encoding regexp match (US-ASCII regexp with UTF-16LE string)
Run Code Online (Sandbox Code Playgroud)

如果你阅读了文档,那么gsub第一个参数就变成了一个Regexp,它被证明是可编码的!那么,让我们试试......

irb(main):005:0> c.gsub("0.0.0.0".encode("UTF-16LE"),"0.0.5.0".encode("UTF-16LE"))
=> myproduct.dll\"\r\n            VALUE \"ProductName\", \"My Product\"\r\n            VALU
E \"ProductVersion\", \"0.0.5.0\"\r\n        END\r\n    END\r\n    BLOCK \"VarFileInfo\"\r
\n    BEGIN\r\n        VALUE \"Translation\", 0x409, 1200\r\n    END\r\nEND\r\n\r\n#endif
Run Code Online (Sandbox Code Playgroud)

您可以在我提供的代码段中看到一些替代品.