【问题标题】:Comparison of Non ASCII only works in IDLE非 ASCII 的比较仅在 IDLE 中有效
【发布时间】:2026-01-05 18:35:01
【问题描述】:

我正在编写一个相当简单的代码,将欧洲葡萄牙语输入转换为巴西葡萄牙语——因此有很多重音字符,例如 á、é、À、ç 等。

基本上,目标是从一个列表中找到文本中的单词,并将它们替换为第二个列表中的 BR 单词。

代码如下:

#-*- coding: latin-1 -*-

listapt=["gestão","utilizador","telemóvel"]
listabr=["gerenciamento", "usuário", "celular"]

while True:

    #this is all because I need to be able to input multiple lines of text, seems to be working fine 

    print ("Insert text")
    lines = []

    while True:
        line = raw_input()
        if line != "FIM":
            lines.append(line)
        else:
            break
    text = '\n'.join(lines)    

    for word in listapt:
        if word in text:
            num = listapt.index(word)
            wordbr = listabr[num]
            print(word + " --> " + wordbr) #just to show what changes were made
            text = text.replace(word, wordbr)

    print(text)

我使用 IDLE 并双击 .py 文件在 Windows 上运行代码。 该代码在使用 IDLE 时运行良好,但在双击 .py 文件时无法匹配和替换字符。

【问题讨论】:

  • 如果在某处添加基本的print "gestão",是否会收到相同的错误消息?
  • 不,我不知道。这似乎工作正常。
  • 我用一个新问题编辑了这个问题——它可以通过 IDLE 工作,但是当我直接运行或转换为 exe 时它不会。为什么?
  • “转换为exe”是什么意思?
  • 我使用 py2exe 创建了一个可执行文件,只是为了测试它,因为它可能会成为这个的最终目标。

标签: python windows python-2.7 character-encoding


【解决方案1】:

这就是代码在 IDLE 中按预期工作但不能通过 CMD 或双击运行的原因:

  1. 您的代码是 UTF-8 编码的,而不是 latin-1 编码的
  2. IDLE 始终在 UTF-8“输入/输出”模式下工作。
  3. 在 Windows 上,CMD/双击将使用非 UTF-8 8 位语言环境。
  4. 当您的代码将输入与硬编码字符串进行比较时,它是在字节级别进行的。在 IDLE 上,它将 UTF-8 与硬编码的 UTF-8 进行比较。在 CMD 上,它将非 UTF-8 8 位与硬编码的 UTF-8 进行比较(如果您使用的是 MacOS,它也可以工作)。

解决此问题的方法是确保您将“苹果与苹果”进行比较。您可以通过将所有内容转换为相同的编码来做到这一点。例如。将输入读取转换为 UTF-8,使其与硬编码字符串匹配。更好的解决方案是将所有 [byte] 字符串转换为 Unicode 字符串(没有编码的字符串)。如果您使用的是 Python 3,这将是全部自动的。

在 Python 2.x 上,您需要做三件事:

  1. 在所有源代码字符串前加上u,使其成为Unicode字符串:

    listapt=[u"gestão",u"utilizador",u"telemóvel"]
    listabr=[u"gerenciamento",u"usuário", u"celula]
    ...
    if line != u"FIM":
    

    或者,添加from __future__ import unicode_literals 以避免更改所有代码。

  2. 使用正确的编码标头对文件进行编码。我怀疑你的标题应该是utf-8。例如

    #-*- coding: utf-8 -*-
    
  3. raw_input 的结果转换为Unicode。这必须通过检测到的标准输入编码来完成:

    import sys
    line = raw_input().decode(sys.stdin.encoding) 
    

顺便说一句,更好的方法是对单词列表进行建模以替换它以使用 dict。键是原词,值是替换词。例如

words = { u"telemóvel": u"celula"}

【讨论】:

  • 天哪!有效!谢谢!关于您的最后一条笔记,这是一个非常好的提示,也非常感谢!
  • 请注意,Windows 控制台是 UTF-16,但默认情况下 Python 2 从控制台读取最适合(非严格)的字节字符串。这使用控制台的当前输入代码页,默认为系统区域设置的 OEM 代码页(例如西欧的 850)。您将阅读此代码页中未定义的所有字符(例如“αβγδε”->“aß?de”)的 mojibake 废话。唯一可靠的解决方案是使用控制台的 Unicode API(例如ReadConsoleW),就像 Python 3.6+ 一样。在 Python 2 中,您可以安装并启用 win_unicode_console 包。
  • 没有理由在这个答案中提到 CMD,因为 OP 通过双击文件来运行脚本。将 CMD 带入讨论会导致混淆,即控制台和 CMD 是同一事物。 cmd.exe 和 python.exe 都是控制台应用程序,它们要么继承要么分配由系统实现的控制台窗口(在 Windows 7+ 中由 conhost.exe,但它是一个实现细节)。
【解决方案2】:

我没有看到这个问题。

根据您对 raw_input 的使用,您似乎使用的是 Python 2.x

这可能是因为我正在复制粘贴堆栈溢出,并且对您有不同的开发环境。

尝试在最新的 Python 3 解释器下运行您的脚本,并删除“#-*- coding:”行。

这应该在您的代码中更快地遇到 UnicodeDecodeError 问题,或者工作正常。

您在这里遇到的问题是 Python 2.x 在尝试在字节序列(Python 2.x 字符串包含的内容,例如二进制文件内容)和人类有意义的文本(unicode,例如诸如中文字符的用户信息显示),因为它对人类可读文本如何编码为 Python 字符串中的字节序列做出了错误的假设。

这是 Python 3 试图更好/不那么含糊地解决的一个细节。

【讨论】:

  • 我试过了,我实际上可以在 IDLE 中运行它,但是如果我双击文件或从 cmd 打开它就不起作用。这样做的最终目标可能是创建一个可共享的可执行文件,因此从 IDLE 运行是不够的。为什么会这样?
【解决方案3】:

首先尝试执行下面的代码,应该可以解决问题:

# -*- coding: latin-1 -*-

listapt=[u"gestão",u"utilizador",u"telemóvel"]
listabr=[u"gerenciamento",u"usuário", u"celular"]

lines=[]
line = raw_input()
line = line.decode('latin-1')
if line != "FIM":
    lines.append(line)

text = u'\n'.join(lines)    

for word in listapt:
    if word in text:
        print("Hello")
        num = listapt.index(word)
        print(num)
        wordbr = listabr[num]
        print(wordbr) 

【讨论】:

  • 不要硬编码decode - 这假设终端正在使用latin-1。当他们双击或从 CMD 运行时,这可能适用于 OP。它在 IDLE 中不起作用。