【问题标题】:encode hash in utf-8以 utf-8 编码散列
【发布时间】:2019-03-31 05:04:51
【问题描述】:

我想用哈希替换子字符串 - 所述子字符串包含非 ascii 字符,因此我尝试将其编码为 UTF-8。

result = re.sub(r'(Start:\s*)([^:]+)(:\s*)([^:]+)', lambda m: m.group(1) + m.group(2) + m.group(3) + hashlib.sha512(m.group(4).encode()).hexdigest(), line.encode('utf-8'))

我不确定为什么这不起作用,我认为使用 line.encode('utf-8'),整个字符串都会被编码。 我还尝试将我的 m.groups 编码为 UTF-8,但我得到了相同的 UnicodeDecodeError。

[unicodedecodeerror: 'ascii' 编解码器无法在位置解码字节 序数不在范围内(128)]

示例输入:

Start: myUsername: myÜsername:

我错过了什么?

EDIT_

Traceback (most recent call last):
  File "C:/Users/Peter/Desktop/coding/filter.py", line 26, in <module>
    encodeline = line.encode('utf-8')
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 112: ordinal not in range(128)

【问题讨论】:

  • 能否请您发布示例输入和您提到的错误的堆栈跟踪? (一般来说,你的问题似乎不是MCVE)。
  • 你是对的,对不起 - 我提供了更多信息
  • 这是 Python 2 还是 Python 3 代码?我强烈怀疑你的问题是你在 Python 2 上运行,并试图 encodestr (这在很大程度上是荒谬的)。完整的回溯和minimal reproducible example 会有所帮助。最后,可以肯定的是,拆分线路,以便每行仅encode 一次,例如encodedline = line.encode('utf-8'),然后将re.sub 中的line.encode('utf-8') 替换为encodedline,这样您就不会混淆哪个encode 是问题所在。
  • 我正在运行 python 2.7 - 有没有办法解决这个问题或者我应该使用“hack”?
  • @peacemaker: hack 是个坏主意(setdefaultencoding 在调用它之后从sys 中删除是有原因的;更改默认的中期运行风险可能会导致各种库中的各种问题已经缓存了编码,或者在其中编码的结果,突然发现事情的行为与启动时不同)。我强烈怀疑您的代码将通过删除该行中对encode 的所有调用来工作;您已经拥有 UTF-8 编码数据,因此再次尝试encode 是您问题的根源。见my answer

标签: python unicode utf-8 ascii


【解决方案1】:

根据您的症状,您在 Python 2 上运行。在 Python 2 str 上调用 encode 几乎总是荒谬的。

你有两个问题;一个你现在打的,如果你修复你当前的代码你会打的。

您的第一个问题是line 已经在(显然)UTF-8 编码字节中是str,而不是unicode,所以encodeing它使用 Python 的默认编码隐式解码(ASCII;这不是我所知道的特定区域设置,而且它是一个罕见的使用其他任何东西的 Python 2 安装),然后重新-使用指定的编解码器进行编码(如果未指定,则使用默认编解码器)。基本上,line 已经被 UTF-8 编码,你告诉它把 again 编码为 UTF-8,但这是荒谬的,所以 Python 首先尝试将 decode 编码为 ASCII,甚至在它之前就失败了按照您的指示尝试encode

解决这个问题的方法就是不要encode line;它已经是 UTF-8 编码的,所以你已经是金子了。

您的第二个问题(您尚未遇到,但您会遇到)是您在 group(4) 结果上调用 encode。但是当然,由于输入是str,所以组也是str,你在尝试encodestr时会遇到同样的问题;由于该组来自原始 UTF-8 编码字节,因此它的非 ASCII 部分在编码之前的隐式解码步骤中会导致 UnicodeDecodeError

原因:

import sys

reload(sys)
sys.setdefaultencoding('UTF8')

有效的是它(危险地)将隐式解码步骤更改为使用 UTF-8,因此您的所有 encode 调用现在都使用 UTF-8 而不是 ASCII 执行隐式 decodedecodeencode 基本上是毫无意义的,因为它所做的只是在通过 decode 确认它是合法的 UTF-8 后返回原始的 str,否则充当昂贵的无操作.

要解决第二个问题,只需更改:

m.group(4).encode()

到:

m.group(4)

这使您的最终代码为:

result = re.sub(r'(Start:\s*)([^:]+)(:\s*)([^:]+)',
                lambda m: m.group(1) + m.group(2) + m.group(3) + hashlib.sha512(m.group(4)).hexdigest(),
                line)

或者,如果您想确认您的预期 line 实际上已经是 UTF-8 编码字节,请在 re.sub 行的上方添加以下

try:
    line.decode('utf-8')
except Exception as e:
    sys.exit("line (of type {!r}) not decodable as UTF-8: {}".format(line.__class__.__name__, e))

如果给定的数据不是合法的UTF-8,这将导致程序立即退出(并且还会让您知道line是什么类型,因此您可以确定它是否真的是str或@987654354 @,因为str 表示您选择了错误的编解码器,而unicode 表示您的输入不是预期的类型)。

【讨论】:

    【解决方案2】:

    我发现 .. 在我眼中是一种解决方法。 虽然感觉不太对劲,但确实有效。

    import sys
    
    reload(sys)
    sys.setdefaultencoding('UTF8')
    

    我认为可以用 .encode('utf-8') 来完成

    【讨论】:

    • 这只是一个技巧,但不是真正的解决方案。但是如果不了解您的字符串等,我们将无法提供帮助
    猜你喜欢
    • 2021-02-18
    • 2017-06-20
    • 2015-08-06
    • 2011-01-01
    • 2011-10-30
    • 2014-06-09
    • 2012-11-07
    • 1970-01-01
    • 2015-03-04
    相关资源
    最近更新 更多