【问题标题】:Solving error: unmappable character for encoding UTF8解决错误:用于编码 UTF8 的不可映射字符
【发布时间】:2013-08-17 14:34:52
【问题描述】:

我有一个 maven 项目,在我的父 pom 中字符编码设置为 UTF-8。

    <plugin>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>2.3.2</version>
      <configuration>
        <source>1.7</source>
        <target>1.7</target>
        <encoding>UTF-8</encoding>
      </configuration>
    </plugin>

但在 Java 文件中,使用了一些字符,如 ` or,这对我造成了编译错误。

在Eclipse(属性----资源-----文本文件编码和Windows--首选项---工作区---文本文件编码)中,我已将编码指定为UTF-8。请让我知道如何解决此问题。

执行转换的 PERL 代码

use strict;
use warnings;
use File::Find;
use open qw/:std :utf8/;

my $dir = "D:\\files";


find({ wanted => \&collectFiles}, "$dir");

sub collectFiles {
    my $filename = $_;
        if($filename =~ /.java$/){
        #print $filename."\n";
        startConversion($filename);
    }
}

sub startConversion{
    my $filename = $_;
    print $filename."\n";
    open(my $INFILE,  '<:encoding(cp1252)',  $filename) or die $!;
    open(my $OUTFILE, '>:encoding(UTF-8)', $filename) or die $!;
}

【问题讨论】:

  • 您是否检查过导致异常的文件确实是 UTF-8 编码的?
  • 请注意,我的项目中存在 3000 个 java 文件,因此手动访问每个文件并将其保存为 utf 编码不是正确的方法。有没有 perl 脚本可以解决这个问题
  • 在问题中发布该代码,然后用 Perl 重新标记它。您在问为什么 perl 脚本不起作用。这与 Java 关系不大。
  • ` 是有效的 ASCII/UTF-8,因此您可能需要在别处查找问题字符。您为什么不直接计算出您的文件使用什么字符编码并将其设置为 Eclipse 中的编码类型。您的 pom.xml 可以保持定义为 UTF-8,因为我怀疑它是否包含任何非 ASCII 字符
  • “它给我造成了编译错误”并不是一个很好的问题描述。什么错误,对于初学者?

标签: java perl maven utf8-decode


【解决方案1】:

如果您使用的是 Linux 或 Mac OS X,则可以使用 iconv 将文件转换为 UTF-8。 Java 1.7 不允许非 utf8 字符,但 Java 1.6 允许(尽管它会产生警告)。我知道是因为我的 Mac 上有 Java 1.7,因此我无法编译我们的一些代码,而 Windows 用户和我们的 Linux 持续构建机器可以,因为他们都仍然使用 Java 1.6。

您的 Perl 脚本的问题是您打开一个文件进行读取和相同的文件进行写入,但您使用的是相同的文件名。当您打开文件进行写入时,您正在删除其内容。

#! /usr/bin/env perl
use warnings;
use strict;
use feature qw(say);

use File::Find;

use strict;
use warnings;
use autodie;

use constant  {
    SOURCE_DIR       => 'src',
};


my @file_list;
find {
    next unless -f;
    next unless /\.java$/;
    push $file_list, $File::Find::name;
}, SOURCE_DIR;

for my $file ( @file_list ) {
    open my $file_fh, "<:encoding(cp1252)", $file;
    my @file_contents = <$file_fh>;
    close $file_fh;

    open my $file_fh, ">:encoding(utf8)", $file;
    print {$file_fh} @file_contents;
    close $file_fh;
}

注意我正在将整个文件读入内存,这对于 Java 源代码应该没问题。即使是庞大的源文件(10,000 行长,平均行长为 120 个字符)也将超过 1.2 兆字节。除非您使用的是 TRS-80,否则 1.2 兆字节的文件不应该是内存问题。如果您想严格一点,请使用File::Temp 创建一个要写入的临时文件,然后使用File::Copy 重命名该临时文件。两者都是标准 Perl 模块。

您也可以将整个程序包含在find 子例程中。

【讨论】:

    【解决方案2】:

    这两行不启动也不执行重新编码:

    open(my $INFILE,  '<:encoding(cp1252)',  $filename) or die $!;
    open(my $OUTFILE, '>:encoding(UTF-8)', $filename) or die $!;
    

    使用&gt; 打开文件会截断它,从而删除内容。有关详细信息,请参阅open documentation

    相反,您必须从第一个文件中读取数据(自动解码),然后将其写回另一个文件(自动对其进行编码)。因为这里的源文件和目标文件是相同的,而且由于 Windows 下文件处理的怪癖,我们应该将输出写入临时文件:

    use autodie;  # automatic error handling :)
    
    open my $in,  '<:encoding(cp1252)', $filename;
    open my $out, '>:encoding(UTF-8)', "$filename~";  # or however you'd like to call the tempfile
    print {$out} $_ while <$in>;  # copy the file, recoding it
    close $_ for $in, $out;
    
    rename "$filename~" => $filename;  # BEWARE: doesn't work across logival volumes!
    

    如果文件足够小(提示:通常是源代码),那么您也可以将它们加载到内存中:

    use File::Slurp;
    
    my $contents = read_file $filename, { binmode => ':encoding(cp1252)' };
    write_file $filename, { binmode => ':encoding(UTF-8)' }, $contents;
    

    【讨论】:

    • 所以这意味着编写 perl 确实是解决这个问题的正确方法......因为涉及到大约 3000 个文件
    • @user2604052 我不知道,因为我认为在默认设置下或不使用非 ASCII 字符时不需要重新编码文件。我的回答只是指出你当前的 Perl 脚本是如何工作的。
    • 是的,你是对的......如果我们从项目本身开始就遵循 utf-8 编码,这不是必需的......但在我的情况下,因为文件是 ansi 格式。 ....我相信这应该将它们从 ansi 转换为 utf-8,从而解决编译错误
    猜你喜欢
    • 2012-07-06
    • 1970-01-01
    • 2012-02-17
    • 2012-12-15
    • 1970-01-01
    • 2019-02-04
    • 2012-11-05
    • 2011-06-27
    • 2015-02-24
    相关资源
    最近更新 更多