【问题标题】:UTF-8 latin-1 conversion issues, python djangoUTF-8 latin-1 转换问题,python django
【发布时间】:2010-09-21 10:07:29
【问题描述】:

好的,所以我的问题是我有字符串 '\222\222\223\225',它在数据库中存储为 latin-1。我从 django 得到的(通过打印它)是以下字符串,'ââââ¢' 我认为它是它的 UTF 转换。现在我需要将字符串传递给一个函数 执行此操作:

strdecryptedPassword + chr(ord(c) - 3 - intCounter - 30)

我得到这个错误:

chr() arg 不在范围内(256)

如果我首先尝试将字符串编码为 latin-1,则会收到此错误:

'latin-1' 编解码器无法对位置 0-3 中的字符进行编码:序数不是 在范围内(256)

我已经阅读了一堆关于字符编码如何工作的文章,但我缺少一些东西,因为我只是不明白!

【问题讨论】:

    标签: python django utf-8 character-encoding


    【解决方案1】:

    您的第一个错误“chr() arg not in range(256)”可能意味着您的值下溢,因为 chr 不能接受负数。我不知道当 inputcounter + 33 大于实际字符表示时加密算法应该做什么,你必须检查在这种情况下该怎么做。

    关于第二个错误。您必须对常规字符串对象进行 decode() 而不是 encode() 才能获得数据的正确表示。 encode() 接受一个 unicode 对象(以 u' 开头的对象)并生成一个常规字符串以输出或写入文件。 decode() 接受一个字符串对象并生成一个带有相应代码点的 unicode 对象。这是通过从字符串对象生成的 unicode() 调用完成的,您也可以改为调用 a.decode('latin-1')。

    >>> a = '\222\222\223\225'
    >>> u = unicode(a,'latin-1')
    >>> u
    u'\x92\x92\x93\x95'
    >>> print u.encode('utf-8')
    ÂÂÂÂ
    >>> print u.encode('utf-16')
    ÿþ
    >>> print u.encode('latin-1')
    
    >>> for c in u:
    ...   print chr(ord(c) - 3 - 0 -30)
    ...
    q
    q
    r
    t
    >>> for c in u:
    ...   print chr(ord(c) - 3 -200 -30)
    ...
    Traceback (most recent call last):
      File "<stdin>", line 2, in <module>
    ValueError: chr() arg not in range(256)
    

    【讨论】:

      【解决方案2】:

      正如 Vinko 所说,Latin-1 或 ISO 8859-1 没有您引用的八进制字符串的可打印字符。根据我对 8859-1 的注释,“C1 控件 (0x80 - 0x9F) 来自 ISO/IEC 6429:1992。它没有定义 80、81 或 99 的名称”。代码点名称与 Vinko 列出的一样:

      \222 = 0x92 => PRIVATE USE TWO
      \223 = 0x93 => SET TRANSMIT STATE
      \225 = 0x95 => MESSAGE WAITING
      

      正确的 UTF-8 编码是(Unicode、二进制、十六进制):

      U+0092 = %11000010 %10010010 = 0xC2 0x92
      U+0093 = %11000010 %10010011 = 0xC2 0x93
      U+0095 = %11000010 %10010101 = 0xC2 0x95
      

      带圆圈的拉丁文小写字母 A 是 ISO 8859-1 代码 0xE2,因此是 Unicode U+00E2;在 UTF-8 中,即 %11000011 %10100010 或 0xC3 0xA2。

      CENT SIGN 是 ISO 8859-1 代码 0xA2,因此是 Unicode U+00A2;在 UTF-8 中,即 %11000011 %10000010 或 0xC3 0x82。

      所以,无论您看到什么,您似乎都没有看到 ISO 8859-1 的 UTF-8 编码。除了所有其他内容之外,您只能看到 5 个字节,而您必须看到 8 个字节。

      添加: 答案的前一部分解决了“UTF-8 编码”声明,但忽略了问题的其余部分,即:

      Now I need to pass the string into a function that does this operation:
      
          strdecryptedPassword + chr(ord(c) - 3 - intCounter - 30)
      
      I get this error: chr() arg not in range(256).  If I try to encode the
      string as Latin-1 first I get this error: 'latin-1' codec can't encode
      characters in position 0-3: ordinal not in range(256).
      

      您实际上并没有向我们展示 intCounter 是如何定义的,但如果它按字符缓慢递增,迟早 'ord(c) - 3 - intCounter - 30' 将是负数(顺便说一下,为什么不结合常量并使用'ord(c) - intCounter - 33'?),此时chr() 可能会抱怨。如果该值为负数,则需要添加 256,或者使用取模运算来确保您有一个介于 0 和 255 之间的正值以传递给 chr()。由于我们看不到 intCounter 是如何递增的,因此我们无法判断它是从 0 循环到 255 还是单调递增。如果是后者,那么您需要一个表达式,例如:

      chr(mod(ord(c) - mod(intCounter, 255) + 479, 255))
      

      当然,其中 256 - 33 = 223,而 479 = 256 + 223。这保证了传递给 chr() 的值是正数,并且对于任何输入字符 c 和任何 intCounter 值都在 0..255 范围内(而且,因为 mod() 函数永远不会得到否定参数,所以无论 mod() 在其参数是否为负时的行为如何,它都可以工作)。

      【讨论】:

      • 所有这些都无关紧要,因为他使用的是自制加密算法。这些字节在解密例程之前并不意味着可打印。这就是为什么我删除了你在这里输入的信息。
      • @Vinko:看起来我处理了第一段,而不是其余的。我会添加一些材料。我想我看到了一个问题(不一定是“那个”问题,但是....)。
      【解决方案3】:

      因为它是用一些可怕的方案加密的,只是通过一些请求改变了字符的 ord(),所以从数据库中出来的字符串已经被加密,这会解密它。您在上面提供的内容似乎不起作用。在数据库中它是 latin-1,django 将其转换为 unicode,但我无法将其作为 unicode 传递给函数,但是当我尝试将其编码为 latin-1 时,我看到了该错误。

      【讨论】:

      • 请用真实的字符串示例输入一些实际代码,因为 u'\222\222\223\225'.encode('latin-1') 适合我
      • 对于 u'\222\222\223\225' 中的 c: print chr(ord(c) - 33) 也可以。它也适用于字符串对象。
      猜你喜欢
      • 2011-05-17
      • 1970-01-01
      • 1970-01-01
      • 2010-10-12
      • 1970-01-01
      • 1970-01-01
      • 2011-01-07
      • 2021-07-29
      • 2015-04-22
      相关资源
      最近更新 更多