键盘输入的umlaut字符(代码页65001,UTF-8)无法被Perl脚本读取

10
请允许我先声明,这个问题严格涉及perl钻石操作符接受直接从键盘输入的内容。
如果我说的是perl钻石操作符接受来自管道或文件中的文本数据,那么这将是519309问题的重复 - 如何使用钻石操作符读取Utf-8
但是,这不是关于管道或文件数据的问题,而是关于直接从键盘键入的输入。因此,我认为,这个问题不是519309的重复。
以下是我的问题详情:
我正在尝试在我的键盘上使用umlaut字符('ä','ö','ü',...)。
我有一个非常简单的perl脚本,它接受来自键盘的行,并立即将其再次打印到屏幕上:
如果我使用代码页1252的umlaut字符,则一切正常:
C:\>chcp 1252 & perl -CS -we"print '*** '; $txt = <>; print '--- ', $txt;"
Page de codes active : 1252
*** ü
--- ü
然而,如果我在使用代码页65001(UTF-8)时使用相同的变音字符,则会收到未初始化值的警告,并且变音符号不被接受:
C:\>chcp 65001 & perl -CS -we"print '*** '; $txt = <>; print '--- ', $txt;"
Page de codes active : 65001
*** ü
Use of uninitialized value $txt in print at -e line 1.
---

如果我将umlaut输入到我的perl程序中,则没有问题:

C:\>chcp 65001 & echo ü | perl -CS -we"print '*** '; $txt = <>; print '--- ', $txt;"
Page de codes active : 65001
*** --- ü

我为什么在使用代码页65001(UTF-8)时会收到此警告?

我正在使用Windows 7 x64和Strawberry Perl 5.22。

只是为了记录,如果我使用纯批处理命令(也就是我不使用perl),那么我可以成功地键入带有代码页65001(UTF-8)的umlaut字符。

C:\>chcp 65001 & set /p txt=*** & echo --- %txt%
Page de codes active : 65001
*** ü
--- ü

问题实际上是:为什么Perl无法接受代码页65001下从键盘输入的umlaut字符,而完全相同的键盘输入,在同样的代码页65001下作为纯DOS批处理命令却可以正常工作?

似乎在通过管道输入umlaut字符和直接从键盘输入umlaut字符之间存在根本的区别。

为什么通过键盘输入umlaut字符不起作用,而以管道形式输入相同的字符却能完美地工作呢?


你尝试过使用选项“-CS”吗?(perl -CS -we)以使STDIN和STDOUT使用UTF-8编码。 - Håkon Hægland
我尝试过perl -CS -we -- 这对于打印到STDOUT非常完美,但出于某种原因,它对STDIN没有影响(也就是说:我仍然有完全相同的问题--未初始化的值) - user2288349
1
CHCP 65001 在 cmd 中与 perl 等外部应用程序一起使用时,utf-8 支持不够稳定。这就是像 ConEmu 这样的包装器派上用场的地方。 - wOxxOm
@wOxxOm 我认为我的代码页65001的问题在于CMD.exe和perl.exe之间的交互 - 就STDOUT而言,一切都正常工作,但STDIN仍然无法正常工作,即使使用perl -CS -we也是如此。 - user2288349
我猜这是perl本身的输入函数,因为即使输入xzüxz也会出现“使用未初始化的值$ txt...”的错误消息。当至少有一个umlaut和´时,完整的输入将被丢弃。我猜这是大于127的每个字符。 - jeb
你是否尝试使用open编译指示符,同时辩称你的问题不是519309的重复? - JosefZ
2个回答

2

尝试将控制台字体更改为“Lucida Console”

您还可以尝试在控制台中运行chcp 65001命令。此命令将字符设置为UTF-8。

如果出现错误显示,请在系统中安装所需的字体。

更多详细信息请点击此处

实际上,问题不属于perl。它属于Windows终端。在这个控制台中尝试一下。您可以将从输入读取的二进制数据记录到某个文件,并比较这两种情况(终端VS cygwin)


1
这是一个微软的bug。Windows APIs中的ReadFile()ReadConsoleA()在代码页65001上始终返回0字节(表示EOF)。有关详细信息,请参见this blog
由于微软不会修复此问题,唯一可用的解决方案是告诉Perl维护者切换到使用ReadConsoleW(),并使用WideCharToMultiByte(CP_UTF8, ...)将结果宽字符转换为utf-8。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接