perl保存utf-8文本问题

时间:2011-06-29 16:04:18

标签: perl utf-8 filehandle

我正在玩pplog,一个单一的文件基础博客。

写入文件代码:

open(FILE, ">$config_postsDatabaseFolder/$i.$config_dbFilesExtension");

my $date = getdate($config_gmt);
print FILE $title.'"'.$content.'"'.$date.'"'.$category.'"'.$i;    # 0: Title, 1: Content, 2: Date, 3: Category, 4: FileName
print 'Your post '. $title.' has been saved. <a href="?page=1">Go to Index</a>';
close FILE;

输入文字:

春眠不覺曉,處處聞啼鳥. 夜來風雨聲,花落知多小.

存储到文件后,它变为:

春眠不覺�›�,處處聞啼鳥.  夜來風�›�聲,花落知多小.

我可以使用Eclipse编辑文件并使其渲染正常。打印到文件期间存在问题。

一些基本信息: 草莓perl 5.12 不使用utf8; 尝试使用utf8;,没有效果。

谢谢。

---编辑--- 感谢您的评论。我追踪了代码:

代码添加新内容:

# Blog Add New Entry Page

    my $pass = r('pass');


        #BK 7JUL09 patch from fedekun, fix post with no title that caused zero-byte message...  
        my $title = r('title');
        my $content = '';
        if($config_useHtmlOnEntries == 0)
        {
            $content = bbcode(r('content'));
        }
        else
        {
            $content = basic_r('content');
        }
        my $category = r('category');
        my $isPage = r('isPage');

sub r
{
    escapeHTML(param($_[0]));
}

将命令转发到CGI.pm函数。

在CGI.pm

sub escapeHTML {
     # hack to work around  earlier hacks
     push @_,$_[0] if @_==1 && $_[0] eq 'CGI';
     my ($self,$toencode,$newlinestoo) = CGI::self_or_default(@_);
     return undef unless defined($toencode);
     $toencode =~ s{&}{&amp;}gso;
     $toencode =~ s{<}{&lt;}gso;
     $toencode =~ s{>}{&gt;}gso;
     if ($DTD_PUBLIC_IDENTIFIER =~ /[^X]HTML 3\.2/i) {
     # $quot; was accidentally omitted from the HTML 3.2 DTD -- see
     # <http://validator.w3.org/docs/errors.html#bad-entity> /
     # <http://lists.w3.org/Archives/Public/www-html/1997Mar/0003.html>.
        $toencode =~ s{"}{&#34;}gso;
     }
     else {
        $toencode =~ s{"}{&quot;}gso;
     }

    # Handle bug in some browsers with Latin charsets
    if ($self->{'.charset'} 
            && (uc($self->{'.charset'}) eq 'ISO-8859-1'    # This line cause trouble. it treats Chinese chars as ISO-8859-1
            || uc($self->{'.charset'}) eq 'WINDOWS-1252')) {
                $toencode =~ s{'}{&#39;}gso;
                $toencode =~ s{\x8b}{&#8249;}gso;
                $toencode =~ s{\x9b}{&#8250;}gso;
        if (defined $newlinestoo && $newlinestoo) {
            $toencode =~ s{\012}{&#10;}gso;
            $toencode =~ s{\015}{&#13;}gso;
        }
    }
    return $toencode;
}

进一步追踪问题,发现浏览器默认为iso-8859-1,甚至手动设置为utf-8,它将字符串发送回服务器为iso-8859-1。

最后,

print header(-charset => qw(utf-8)), '<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />

添加-charset =&gt; qw(utf-8)param to header。中国诗仍然是中国诗。

感谢Schwern的评论,它激励我找出问题并学习leeson。

3 个答案:

答案 0 :(得分:2)

为了让utf8真正在Perl中工作,需要翻转很多个人功能。 use utf8只使代码utf8(字符串,变量,正则表达式......),你必须单独执行文件句柄。

它很复杂,最简单的方法是使用utf8::all,这将使utf8成为代码,文件,@ ARGV,STDIN,STDOUT和STDERR的默认值。在Perl中,utf8支持不断改进,utf8 :: all将在可用时添加它。

答案 1 :(得分:0)

我不确定您的代码如何产生该输出 - 例如,缺少引号。当然,这可能是由于文件和我看到页面之间的“腐败”。 SO可以过滤损坏的UTF-8。我建议将来提供十六进制转储!

无论如何,要在Perl中使用UTF-8输出,有几种方法:

  1. 使用字符数据,即让Perl知道您的变量包含Unicode。这可能是最好的方法。确认utf8::is_utf8($var)为真(您需要,而不应 use utf8为此)。如果没有,请查看Encode模块的decode函数,以使Perl知道其Unicode。一旦Perl知道您的数据是字符,那么该打印将发出警告(您确实启用了它,对吧?)。要解决此问题,请在文件上启用:utf8:encoding(utf8)图层(后一版本提供错误检查)。您可以在打开(open FILE, '>:utf8', "$fname")中执行此操作,也可以使用binmode(binmode FILE, ':utf8')启用它。请注意,您还可以使用其他编码;请参阅encodingPerlIO::encoding文档。

  2. 将您的Unicode视为不透明的二进制数据。 utf8::is_utf8($var)必须是假的。操纵琴弦时一定要非常小心;例如,如果你有UTF-16-BE,那么这不是一个好主意:print "$data\n",因为你实际上需要print $data\0\n"。 UTF-8的问题较少,但您需要了解它们。

  3. 我建议阅读perluniintro,perlunitut,perlunicode和perlunifaq manpages / pods。

    此外,use utf8;只告诉Perl你的脚本是用UTF-8编写的。它的影响非常有限;看它的pod文档。

答案 2 :(得分:0)

您没有显示实际运行的代码。我使用Cygwin上的5.10.1和Windows上的5.12.3成功处理了您提供的文本作为输入。所以我怀疑你的代码中有一个错误。尝试通过编写一个简短,独立的测试用例来缩小问题范围。