【问题标题】:UnicodeDecodeError occurring in one context but not in another, while the context itself seems irrelevant. Clarification?UnicodeDecodeError 发生在一个上下文中但不在另一个上下文中,而上下文本身似乎无关紧要。澄清?
【发布时间】:2015-10-19 19:40:53
【问题描述】:

我有以下代码:

outlines = ""
foundnameslistlist = []
suggnameslistlist = []

filenames = []

fl = 0
flen = len(os.listdir(InputDir))
for filen in os.listdir(InputDir):
    if filen.endswith(".txt"):
        fl += 1
        foundnameslist = "\n*****************\n\n Names found--------\n"
        suggnameslist = "\n Names suggested--------\n"
        sourcefile = open(InputDir + '\\' + filen,'r')
        NLStrings = sourcefile.readlines()
        for NLS in NLStrings:
            ug = getunigrams(NLS.lower())
            nf = NField(ug, ndict, ncontextsdict, abscontextsdict)

            for fn in nf[0]:
                foundnameslist += "'" + fn[1] + "' in '" + ' '.join(fn[2]) + "'\n"
            for sn in nf[1]:
                suggnameslist += "'" + sn[1] + "' in '" + ' '.join(sn[2]) + "'\n"

        outlines += "File name: " + filen + foundnameslist + suggnameslist + "\n###################\n"

        foundnameslistlist.append(foundnameslist)
        suggnameslistlist.append(suggnameslist)

    if fl % 50 == 0:
        print(str(float(fl* 100)/flen) + "% of files completed.")

产生错误:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python27\lib\lib-tk\Tkinter.py", line 1486, in __call__
    return self.func(*args)
  File "F:\GNameHunt\NameFinderBeta.py", line 357, in ExecuteButtonClick
    NameExtract(InputButtonString.get(),OutputButtonString.get())
  File "F:\GNameHunt\NameFinderBeta.py", line 311, in NameExtract
    outlines += "File name: " + filen + foundnameslist + suggnameslist + "\n###################\n"
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 367: ordinal not in range(128)

我收到此错误的事实向我表明,我对事物如何工作的心理模型存在缺陷(即,为什么它允许我在没有任何特殊编码的情况下创建字符串 foundnameslist 和 suggnameslist 而没有错误,然后突然当我将它们与轮廓连接时失败了吗?显然肯定有一些我不理解的东西)。我还感兴趣(和困惑)的是,这段代码 sn-p 确实在另一个上下文中工作而不会产生任何错误。在这里,它包含在通过 TKinter GUI 访问的函数中,但是当我将此 sn-p 作为独立脚本的一部分运行时,即使两个实例的输入相同,也不会发生错误。

我已经尝试将这个 sn-p 中的每个字符串抢先编码为 utf-8、utf-16 和 utf-32,所有这些都会产生稍微不同的 UnicodeDecodeError 变体......甚至更糟;当我让它为调试目的输出有问题的字符串时,一些字符串只包含正常的 ascii 字符——没有任何奇怪的东西,变音符号或其他。一致的事情是触发错误的总是同一行:“outlines += ...”

您可以在此处提供的任何见解将不胜感激。

编辑澄清:使用 python 2.7

编辑 2:要遵循的更多上下文

名为 NFind 的函数本身在直接从脚本调用时会产生正确的输出。

sourcestring = os.getcwd() + "\\Matt Files"
NFind(sourcestring, "NameOutput.txt")

但是,相关的TKinter代码:

    def IButtonClick():
        InputButtonString.set(askdirectory())

    def OButtonClick():
        OutputButtonString.set(askopenfilename())

    def ExecuteButtonClick():
        NFind(InputButtonString.get(),OutputButtonString.get())

在选择适当的输入目录和适当的输出文件后产生错误。

出于好奇,我在 NFind 的开头放了以下两行:

print InputDir
print OutputF

在 TKinter 之外调用 NFind(产生正确、无错误的输出),我得到了

F:\GNameHunt\Matt Files
NameOutput.txt

在 TKinter 内部调用 NFind(产生错误),我得到了

F:/GNameHunt/Matt Files
F:/GNameHunt/NameOutput.txt

【问题讨论】:

  • 了解如何在每个上下文中调用此代码可能会有所帮助,因为上下文似乎是问题的根源。一旦发现差异,解决起来就会容易得多。
  • 从 Tkinter 而不是从独立脚本调用时发生错误的事实确实表明问题与 Tkinter 有关。在某个地方,它需要字符串是 ASCII(最简单的 7 位编码),而它遇到的字符串不是。独立脚本显然不包含绝对需要 ASCII 的路径。
  • 顺便说一句,当涉及到 Python 2 中的字符串时,不要对自己的心智模型过于苛刻。像这样难以调试的错误有助于激发字符串的设计和实现Python 3. 你需要知道的主要事情(不管你使用的是什么编程语言)是保持“字符串”(又名 Unicode)的柏拉图式理想与其实际编码表示之间的区别(通常也令人困惑称为字符串,但实际上应该称为“字节序列”)。
  • 我添加了更多上下文,希望可以诊断出确切的问题。大多数时候我对 Python 2 非常满意,直到现在还没有遇到太多字符串不兼容问题。也就是说,迁移到 Python 3 听起来肯定更有吸引力。
  • 感谢您添加更多信息。我不认为斜杠与反斜杠的事情应该有所作为。 Python应该能够处理它。 (如果有的话,我希望反斜杠更有可能导致问题。)您可以通过将 F:/GNameHunt/Matt FilesF:/GNameHunt/NameOutput.txt 输入到非 Tkinter 调用中进行测试,看看它是否仍然有效。这应该。还有两件事:(1)在某些时候,函数显然从NameExtract 更改为NFind。这可能会让阅读您的问题的人感到困惑。 (2) 调试时,用print repr(x)代替print x

标签: python string unicode codec utf


【解决方案1】:

我可以建议使用 python 格式化工具连接你的字符串而不是把它们加在一起吗?

例如:

foundnameslist += "'{0}' in '{1}'\n".format(fn[1], ' '.join(fn[2])) 

outlines += "File name: {0}{1}{2}\n###################\n".format(filen.decode('utf8'), foundnameslist.decode('utf8'), suggnameslist.decode('utf8'))

问题也可能在您加入的列表中。其中一项可能与其他项不兼容。

如果utf8 不起作用,请尝试latin1

不看文件内容,很难弄明白。

帮助您调试:

try:
    outlines += "File name: {0}{1}{2}\n###################\n".format(filen.decode('utf8'), foundnameslist.decode('utf8'), suggnameslist.decode('utf8'))
except UnicodeDecodeError as e:
    print(e)
    print(filen)
    print(foundnameslist)
    print(suggnameslist)
    continue

这将打印出带有违规信息的错误,但会继续运行

结帐pyformat - 非常有帮助

【讨论】:

  • 我喜欢这种风格,但我不确定我是否理解我加入的列表中的问题,因为错误总是发生在“输出 += ... " 行和从未有过的
  • 好吧,根据错误,它认为它不是 ascii ......我正在修改我的代码,希望它是 utf-8 并且您使用的是 python 2.6+ - 我是在字符串前面添加 u 表示它们是 unicode。
  • 尝试在我的代码中的所有字符串前面添加一个 u,出现同样的错误。
  • 这意味着它可能不是 unicode 字符。无论如何,这是一个源自 Windows 的文件吗?它可能有一些时髦的双引号
【解决方案2】:

我发现通过添加以下行:

InputDir = InputDir.encode('utf-8')
OutputF = OutputF.encode('utf-8')

在 NFind 函数的开头,我能够使其正常工作。按照 John Y 的建议并使用 print repr(x) 而不是 print x,我看到当通过 TKinter 调用 NFind 时,InputDir 和 OutputF 是 unicode 字符串,而不是默认的 python 字符串。 .encode('utf-8') 输出默认字符串等价物(与我的直觉相反,我原以为它们会从默认转换为 unicode,而不是反之亦然。将来对我有更多的学习)。

文件名和目录的字符串类型似乎可以改变读取这些文件的方式,在此之前我不会考虑。

感谢所有贡献的人!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-13
    • 1970-01-01
    • 1970-01-01
    • 2014-07-25
    • 1970-01-01
    • 2015-01-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多