如何从CLI标准输入读取非ASCII字符

16

如果我在CMD中输入å,fgets会停止等待更多的输入,而循环会一直运行直到我按下ctrl-c。如果我输入类似a-z0-9!?()这样的“正常”字符,则按预期工作。

我在Windows 7上使用UTF-8字符集(chcp 65001),文件保存为UTF-8无BOM格式,在CMD中运行PHP 5.3.5(cli)。

<?php

echo "ÅÄÖåäö work here.\n";

while(1)
{
    echo '> '. fgets(STDIN);
}

?>
如果我更改字符集为chcp 1252,当我键入å时循环不会中断,并且它会打印“> å”,但是“ÅÄÖåäö 在这里工作” 变成了“ÅÄÖåäö 在这里工作!”。 我知道我可以将文件更改为ANSI,但然后我不能使用像╠╦╗这样的特殊字符。
那么为什么在键入åäö后fgets停止等待用户输入? 我该如何解决这个问题?
编辑:还发现一个奇怪的错误。 echo "öäåÅÄÖåäö work here! Or?" . chr(10);-> ??äåÅÄÖåäö work here!Or?re!Or?。如果echo中的第一个字符是å / ä / ö ,它会打印出奇怪的字符,并且最终输出会与n-1 个字符重复.. (n =字符串开头的åäö的数量)。例如:echo "åäö 1234" -> ??äö 123434 echo åäöåäö 1234 -> ??äöåäö 1234 1234
编辑2(已解决): 问题是chcp 65001 ,现在我使用chcp 437 chcp 437)。非常感谢Timothy Martens!

关于这个问题有一些疑问:1)当您尝试在PHP之外的CMD中键入 å 时会发生什么?2)逻辑上讲UTF-8 Å和windows-1252 Å不同,因此会导致结果为 Ã。但是如果尝试将PHP文件转换为windows-1252会发生什么? - Qqwy
1) åäö -> "command not found", echo åäö -> åäö。所以它可以工作。无论是使用chcp 65001(UTF-8)还是chcp 1252都可以。 2) 我在cmd中和PHP文件中都使用UTF-8作为字符集。如果我在PHP文件中使用windows-1252,什么也不会改变。我认为问题出在windows/PHP上。当我使用chcp 1252时,它对于ÅÄÖ(即使PHP文件是UTF-8)有效,但是我不能使用╠╦╗等字符。 - Sawny
哇,这是一个非常有趣的问题^^。你真的引起了我的注意。我会自己试验一下,一旦发现什么就告诉你。 - Qqwy
我在想...如果你使用fgetsc(STDIN)会怎样?可能是一样的,但它可能会产生另一个(不需要的?:P)结果... - Qqwy
@Qqwy var_dump(fgetc(STDIN)) -> bool(false); var_dump(fgets(STDIN)) -> bool(false); 当我输入 å (或者 äö) 时,它不起作用。否则它可以正常工作。 - Sawny
2个回答

5
可能的解决方案:
echo '>'; 
$line = stream_get_line(STDIN, 999999, PHP_EOL);

注意: 我使用多个版本的PHP都无法复现您的错误。 使用以下PHP版本5.3.8没有任何问题

PHP 5.3 (5.3.8) VC9 x86非线程安全版(2011年8月23日12:26:18) 架构是Win XP SP3 32位

您可以尝试升级PHP。

我下载了php-5.3.5-nts-Win32-VC6-x86,但无法复制您的错误,它对我来说很好用。

编辑:此外,我使用西班牙键盘输入了这些字符。

编辑2:

CMD命令:

chcp 437

PHP 代码:

<?php
$fp=fopen("php://stdin","r");
while(1){
    $str =  fgets(STDIN);
    echo mb_detect_encoding($str)."\n";
    echo '>'.stream_get_line($fp,999999,"\n")."\n";
}
?>

输出:

test
ASCII
test
>test
öïü

öïü
>öïü

  1. stream_get_line 没有起作用。
  2. 我现在下载了 VC9 x86 Non Thread Safe (2011-Aug-23 12:26:18),但它没有起作用。你在 CMD 和代码中使用了什么字符集?顺便说一下,我运行的是 W7 64 位系统。
- Sawny
1
注意:我刚在我的 Mac 上使用了 PHP 5.3.6 和 PHP 5.2.14 进行了测试,两者都能正常工作。 - Yes Barry
@Sawny 我在 cmd 中使用的是“活动代码页:437”,你可以通过在 cmd 中运行“chcp 437”来更改你的代码页。 - Timothy Martens
我很好奇你的是什么???你可以通过在cmd中运行命令“chcp”来检测它。如果您想获取更多信息,可以在以下链接中找到有关chcp的问题:https://dev59.com/zHM_5IYBdhLWcg3wt1k0 - Timothy Martens
@Sawny 当我输入普通字母时,PHP 报告检测到 ANSI 编码,但当我输入特殊字符时,PHP 没有报告任何信息。我使用 mb_detect_encoding() 函数来告诉我编码是什么。 - Timothy Martens
显示剩余2条评论

2

我认为这是因为PHP 5.3不支持多字节字符。

这些字符:ÅÄÖåäö

是二进制的:c3 85 c3 84 c3 96 c3 a5 c3 a4 c3 b6(没有BOM开头)

引用PHP String

字符串是由一系列字符组成,其中一个字符等同于一个字节。这意味着PHP只支持256个字符集,因此不提供本地Unicode支持。请参阅字符串类型的详细信息。

通常不会影响最终结果,因为浏览器/读者理解多字节字符,但对于CMD和STDIN缓冲区,则为ÅÄÖåäö(12个字符/字节的字符数组)。

只有MB函数才能处理多字节字符串的基本操作。


是的,我知道MB函数,但它们没有任何读取资源函数 :( - Sawny

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