如何在ruby中创建一个带有"错误编码"的字符串?

GSP*_*GSP 5 ruby character-encoding

我有一个生产中的某个文件,我无法访问它,当由ruby脚本加载时,针对内容的正则表达式失败了ArgumentError => invalid byte sequence in UTF-8.

我相信我有一个基于所有要点的答案:ruby 1.9:UTF-8中的无效字节序列

# Remove all invalid and undefined characters in the given string
# (ruby 1.9.3)
def safe_str str

  # edited based on matt's comment (thanks matt)
  s = str.encode('utf-16', 'utf-8', invalid: :replace, undef: :replace, replace: '')
  s.encode!('utf-8', 'utf-16')
end
Run Code Online (Sandbox Code Playgroud)

但是,我现在想构建我的rspec以验证代码是否有效.我无法访问导致问题的文件,所以我想以编程方式创建一个带有错误编码的字符串.

我尝试过以下方面的变化:

bad_str = (100..1000).to_a.inject('') {|s,c| s << c; s}
bad_str.length.should > safe_str(bad_str).length
Run Code Online (Sandbox Code Playgroud)

要么,

bad_str = (100..1000).to_a.pack(c*)
bad_str.length.should > safe_str(bad_str).length
Run Code Online (Sandbox Code Playgroud)

但长度总是一样的.我也尝试过不同的角色范围; 并不总是100到1000.

有关如何在ruby 1.9.3脚本中使用无效编码构建字符串的任何建议?

Hew*_*lff 5

许多单字节字符串将生成无效的 UTF-8 字符串(以 0x80 开头)。所以128.chr应该有效。


mat*_*att 3

您的safe_str方法(当前)实际上永远不会对字符串执行任何操作,它是一个无操作。String#encodeRuby 1.9.3的文档说:

\n\n
\n

请注意,从编码 enc 到相同编码 enc 的转换是无操作,即返回接收者而不进行任何更改,并且不会引发异常,即使存在无效字节也是如此。

\n
\n\n

对于当前版本的 2.0.0(补丁级别 247)来说确实如此,但是最近对 Ruby trunk 的提交改变了这一点,并且还引入了一种scrub几乎可以满足您需求的方法。

\n\n

在发布新版本的 Ruby 之前,您将需要将文本字符串往返到另一种编码并返回以清理它,如您链接到的问题的答案中的第二个示例所示,如下所示:

\n\n
def safe_str str\n  s = str.encode(\'utf-16\', \'utf-8\', invalid: :replace, undef: :replace, replace: \'\')\n  s.encode!(\'utf-8\', \'utf-16\')\nend\n
Run Code Online (Sandbox Code Playgroud)\n\n

请注意,尝试创建无效字符串的第一个示例不会\xe2\x80\x99 工作:

\n\n
bad_str = (100..1000).to_a.inject(\'\') {|s,c| s << c; s}\nbad_str.valid_encoding? # => true\n
Run Code Online (Sandbox Code Playgroud)\n\n

来自<<文档

\n\n
\n

如果对象是整数,则将其视为代码点,并在连接之前转换为字符。

\n
\n\n

所以你\xe2\x80\x99总会得到一个有效的字符串。

\n\n

第二种方法,使用pack将创建一个带有编码的字符串ASCII-8BIT。如果您随后使用以下命令更改此设置,force_encoding则可以创建具有无效编码的 UTF-8 字符串:

\n\n
bad_str = (100..1000).to_a.pack(\'c*\').force_encoding(\'utf-8\')\nbad_str.valid_encoding? # => false\n
Run Code Online (Sandbox Code Playgroud)\n