【问题标题】:Python: Unexpected result when byte 0xe0 is readPython:读取字节 0xe0 时出现意外结果
【发布时间】:2019-02-18 06:00:02
【问题描述】:
import msvcrt
while True:
    try:
        a=msvcrt.getch()
        a=a.decode('utf-8')
        print(a)
    except:
        print(a)

当我输入箭头键或向上翻页/向下翻页/删除等时,上面的代码会产生意想不到的结果。

The output is as follows:
[I/P=a]
a #expected result
[I/P=UP ARROW]
b'\xe0'
H  #unexpected result

我可以理解 b'\xe0' 正在打印,但为什么 H 会随之打印? 执行此操作时未打印 H:

import msvcrt
a=msvcrt.getch()
print(a)#b'\xe0'
a=a.decode('utf-8')
print(a)
When I input UP ARROW here, it raises a UNICODEDECODERROR.

我查看了解释 msvcrt.getch() 如何工作的另一个问题,但这仍然无法解释为什么我在第一段代码中得到两个字符,而在第二段代码中只有一个字符。 为什么 a 不等待输入下一个字符,而是假定值 b'H'?

【问题讨论】:

标签: python encoding msvcrt


【解决方案1】:

箭头键(以及功能键和其他键)需要两次单独调用msvcrt.getch。当您按 ↑ 时,第一个返回 b'\xe0',第二个返回 b\x48这些都不是 UTF-8 甚至 ASCII。第一个不是有效的 UTF-8 序列,这就是您的 decode('utf-8') 调用引发异常的原因。第二个是表示键码 72 的字节值,巧合恰好与表示 UTF-8 或 ASCII 中的字母 'H' 的字节值相同。

来自msvcrt documentation(强调我的):

msvcrt.getch()

读取按键并将结果字符作为字节字符串返回。 控制台没有回显任何内容。 如果按键不可用,此调用将阻塞,但不会等待 Enter 被按下。 如果按下的键是特殊功能键,则返回'\000''\xe0'下一次调用将返回密钥代码。 此功能无法读取 Control-C 按键。

您可以使用这样的程序查看通过的字节数:

import msvcrt

NEXT_CHARACTER_IS_KEYCODE = [b'0xe0', b'0x00']

while True:
  ch1 = msvcrt.getch()
  print("Main getch(): {}".format(ch1))
  if ch1 in NEXT_CHARACTER_IS_KEYCODE:
      ch2 = msvcrt.getch()
      print("  keycode getch(): {}".format(ch2))

请注意,其中没有 .decode('utf-8'),因为 getch 无论如何都不会返回 UTF-8 字节。

(注意:确保你真的想使用msvcrt.getch,因为这是一个非常不寻常的选择,尤其是在 2019 年。)

相关:

【讨论】:

  • 为什么说 getch() 是一个不寻常的选择?
  • getch 是一个奇怪的旧兼容性 API,它需要调用一些键两次,另一些键调用一次,以及知道幻数。它是特定于 Windows 的,实际上是特定范围的旧 Windows 运行时(例如,它不是更现代的通用 Windows 运行时的一部分)。因此,除非您正在做一些非常特别和特别的事情,否则几乎可以肯定会有更好(更方便)的 API 来做。
猜你喜欢
  • 2015-05-30
  • 2017-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-18
  • 2013-11-07
  • 1970-01-01
相关资源
最近更新 更多