为什么在对包含无效UTF-8数据的字符串进行操作时出现Ruby错误,而Python却没有?

时间:2018-01-21 08:51:10

标签: python ruby character-encoding

在Ruby(2.4)中,我可以创建一个字符串,其编码为UTF-8但在UTF-8中包含一个无效的字节(让我们使用字节E1)。

然后当我尝试将正则表达式与此字符串匹配时,我收到错误。

2.4.0 :001 > "Hi! \xE1".match?(//)
ArgumentError: invalid byte sequence in UTF-8
        from (irb):1:in `match?'
        from (irb):1

当我在Python 3中做同样的事情时,我没有收到错误。

>>> import re; re.match('', "Hi! \xE1")
<_sre.SRE_Match object; span=(0, 0), match=''>

我的理解是,在这两种情况下,我都处于犯罪状态,因为我正在创建包含UTF-8中无效字节的UTF-8编码字符串。鉴于:

  • 是否特定的正则表达式比较在Ruby中失败,而不是其他操作?如果是这样,为什么?
  • 这里有什么可以解释Ruby和Python之间的区别?
  • 是否有可能让Python给出这种类型的错误? (没有与外部资源交互 - 我知道这可能发生在连接到数据库的上下文中。)

1 个答案:

答案 0 :(得分:0)

在Ruby中,使用引号(即'Hi!')创建新字符串将创建核心String类的实例。如您所述,在2.0或更高版本中,ruby默认将源文件中的字符串解释为UTF-8。如果然后在字符串实例上调用一个方法,它将使用配置的编码来解释构成字符串的字节并应用该方法(所以为了回答你的第一个问题,它不是特定于正则表达式匹配 - 你会看到如果您调用gsubsplit或任何其他字符串方法,则会出现相同的错误。

作为this post有用的细节,python 3默认将字符串解释为Unicode;但是,当ruby默认为UTF-8时,python 3默认为UTF-16或UTF-32,具体取决于解释器的构建方式,因此\xE1无效。

有趣的是,如果你给python一些不是unicode的十六进制,它似乎把它留作明文:

>>> '\uffff'
'\uffff'

如果你给它废话(非十六进制),它会引发一个错误:

>>> "Hi! \xz1"
  File "<stdin>", line 1
SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in 
position 4-5: truncated \xXX escape