【问题标题】:How to create a string with a "bad encoding" in ruby?如何在 ruby​​ 中创建具有“错误编码”的字符串?
【发布时间】:2013-08-16 14:47:23
【问题描述】:

我在生产中的某个地方有一个文件,我没有可以访问该文件,当由 ruby​​ 脚本加载时,针对内容的正则表达式失败并显示 ArgumentError => invalid byte sequence in UTF-8

我相信我已经根据此处所有要点的答案进行了修复:ruby 1.9: invalid byte sequence in 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

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

我尝试过以下变化:

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

或者,

bad_str = (100..1000).to_a.pack(c*)
bad_str.length.should > safe_str(bad_str).length

但长度始终相同。我也尝试过不同的字符范围;并不总是 100 到 1000。

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

【问题讨论】:

  • 你的坏字符串会触发原来的“无效字节序列”异常吗?也许他们真的很糟糕,但 safe_str 出于某种原因没有抓住它。
  • 谢谢@HewWolff 我还没有部署它。我想让我的测试正常运行(根据下面的 matt 评论,这是一件好事)。

标签: ruby character-encoding


【解决方案1】:

大量单字节字符串会生成无效的 UTF-8 字符串,从 0x80 开始。所以128.chr 应该可以工作。

【讨论】:

  • 谢谢。我忘记了Integer 上的chr 方法。
【解决方案2】:

在我编写的规范测试中,我还没有找到修复这种错误编码的方法:

时期%基础

%B 字符串始终生成ArgumentError: invalid byte sequence in UTF-8

【讨论】:

  • 我不确定您所说的“%”是什么意思?您是否使用它来表示像"Period\xBasics" 这样的十六进制值?
  • 我什至都懒得去检查值映射到什么或它代表什么。通过检查 Airbrake 异常,我意识到了该字符串,而错误字符串来自 GET 参数。我尝试了多种方法来捕获或修复异常,但都没有运气。
【解决方案3】:

您的safe_str 方法(目前)实际上不会对字符串做任何事情,它是无操作的。 String#encode on Ruby 1.9.3 say 的文档:

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

这对于当前版本的 2.0.0(补丁级别 247)是正确的,但是 recent commit to Ruby trunk 改变了这一点,并且还引入了 scrub 方法,几乎​​可以满足您的需求。

在发布新版本的 Ruby 之前,您需要将文本字符串往返传输到另一个编码并返回以清理它,如 this answer to the question you linked to 中的第二个示例所示,类似于:

def safe_str str
  s = str.encode('utf-16', 'utf-8', invalid: :replace, undef: :replace, replace: '')
  s.encode!('utf-8', 'utf-16')
end

请注意,您尝试创建无效字符串的第一个示例将不起作用:

bad_str = (100..1000).to_a.inject('') {|s,c| s << c; s}
bad_str.valid_encoding? # => true

来自&lt;&lt; docs

如果对象是一个整数,它被认为是一个代码点,并在连接之前被转换为一个字符。

所以你总是会得到一个有效的字符串。

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

bad_str = (100..1000).to_a.pack('c*').force_encoding('utf-8')
bad_str.valid_encoding? # => false

【讨论】:

  • 谢谢。 force_encoding 步骤一直让我失望。
  • P.S.我希望我可以访问 ruby​​ 2。scrub 方法正是我所需要的。
【解决方案4】:

试试s = "hi \255"

s.valid_encoding?
# => false

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 2021-11-27
    • 1970-01-01
    • 2022-07-07
    • 2017-03-08
    • 2011-12-01
    相关资源
    最近更新 更多