【问题标题】:Perl drop down menus and UnicodePerl 下拉菜单和 Unicode
【发布时间】:2017-10-27 22:04:51
【问题描述】:

我已经在这个问题上讨论了一段时间,但还是不太明白。这是 Ubuntu 上的 Perl 5。我的网页上有一个下拉列表:

$output .= start_form . "Student: " . popup_menu(-name=>'student', -values=>['', @students], -labels=>\%labels, -onChange=>'Javascript:submit()') . end_form;

这只是来自 SQL Server 表的“Last, First”形式的一组名称。标签是从 SQL 列创建的,如下所示:

$labels{uc($record->{'id'})} = $record->{'lastname'} . ", " . $record->{'firstname'}; 

问题在于下拉菜单未正确显示某些 Unicode 字符。例如,“Søren”在下拉菜单中显示为“Søren”。我的标题中有:

use utf8;
binmode(STDOUT, ":utf8");

...我还尝试了各种“decode()”功能,但无济于事。对我来说,有趣的是,如果我将 $labels 拉入测试脚本并将列表打印到控制台,名称看起来就好了!那么导致这种情况的下降是什么?提前谢谢你。

编辑:

这是相关功能,我已将其简化为在控制台中运行的脚本,为三个具有 Unicode 字符的条目提供正确的结果

#!/usr/bin/perl

use DBI;
use lib '/home/web/library';
use mssql_util;
use Encode;

binmode(STDOUT, ":utf8");

$query = "[SQL query here]";

$dbh  = &connect;
$sth  = $dbh->prepare($query);
$result = $sth->execute();

while ($record = $sth->fetchrow_hashref())
{
        if ($record->{'id'})
        {
                $labels{uc($record->{'id'})} = Encode::decode('UTF-8', $record->{'lastname'} . ", " . $record->{'nickname'} . " (" . $record->{'entryid'} . ")");
        }
}

$sth->finish();

print "$labels{'ST123'}\n";
print "$labels{'ST456'}\n";
print "$labels{'ST789'}\n";

生产脚本所做的不同之处在于,它不是像上面那样打印到控制台,而是打印到 HTTP:

$my_output = "<p>$labels{'ST123'}</p><br>
              <p>$labels{'ST456'}</p><br>
              <p>$labels{'ST789'}</p>";

$template =~ s/\$body/$my_output/;

print header(-cookie=>$cookie) . $template; 

这会在页面上给出诸如“Zoë”和“Søren”之类的字符串。但是,如果我从生产脚本的顶部删除binmode(STDOUT, ":utf8");,则字符串在页面上显示得很好(即我得到“Zoë”和“Søren”)。

我相信在将 UTF-8 写入输出时需要 binmode( ) 行,但在此处删除它会产生正确的结果。什么给了?

【问题讨论】:

  • 您需要检查 $record->{'lastname'} 和 $record->{'firstname'} utf8 标志使用 Encode:is_utf8()。如果它们都是 utf8 或者不是,你可以将它们连接起来。
  • 请为不能正常工作的字符串提供sprintf "%vX", $value 的输出,并提供您希望看到的该字符串的输出。
  • 从不使用Encode::is_utf8,调试语句除外。依赖其结果的代码肯定是有问题的。
  • 谢谢@ikegami。我得到:53.C3.B8.72.65.6E,对于我希望显示为“Søren”但显示为“Søren”的字符串。我的测试脚本正确地将“Søren”和“53.F8.72.65.6E”打印到控制台。
  • 看来我从数据库中读取数据还不错,并且是 HTTP 响应编码导致了问题(我认为,正如 Dave 所建议的那样)。

标签: perl unicode encoding utf-8


【解决方案1】:

问题 1:解码输入

53.C3.B8.72.65.6ESøren 的 UTF-8 编码。当您指示 Perl 重新编码时(通过打印它以使用 :utf8 层处理),您正在产生垃圾。

您需要解码您的输入($record-&gt;{id}$record-&gt;{lastname}$record-&gt;{firstname} 等)!这会将 UTF-8 字节 53.C3.B8.72.65.6E(“编码文本”)转换为 Unicode 代码点 53.F8.72.65.6E(“解码文本”)。

在此表单中,您将能够使用uc、正则表达式匹配等。您还可以将它们打印到带有编码层的句柄(例如:encoding(UTF-8),或不正确的:utf8 )。

您承认这些输入来自数据库。大多数 DBD 都有一个标志,可以使字符串被解码。例如,如果是 MySQL 数据库,则应将mysql_enable_utf8mb4 =&gt; 1 传递给connect


问题 #2:通信编码

如果您要输出 UTF-8,请不要告诉浏览器它是 ISO-8859-1!

$ perl -e'use CGI qw( :standard ); print header()'
Content-Type: text/html; charset=ISO-8859-1

固定:

$ perl -e'use CGI qw( :standard ); print header( -type => "text/html; charset=UTF-8" )'
Content-Type: text/html; charset=UTF-8

【讨论】:

  • 绝对正确。当我删除binmode(STDOUT, ":utf8") 并使用Encode::decode('UTF-8', $record-&gt;{'lastname'} . ", " . $record-&gt;{'nickname'}) - 一切都很好。谢谢您的帮助。我刚刚开始学习编码和字符集的工作原理,所以我很感激大家的耐心。
  • 不!保持binmode(STDOUT, ":utf8")。您需要对输出进行编码!
  • 保留binmode(STDOUT, ":utf8") 会导致输出恢复为垃圾。我很困惑...
  • 那你还有一个问题要解决,你什么也没说。
  • 我用更全面的代码 sn-p 编辑了我的帖子。我想不出还能提供什么,但我非常感谢您的帮助。谢谢。
【解决方案2】:
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-27
  • 1970-01-01
  • 2015-08-08
  • 2020-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多