Maven 更改某些文件的编码

Maven change encoding to certain files

我的所有项目都采用 Cp1252 编码,但我用 UTF-8 编码的几个文件除外,它们包含特殊字符。

当我 运行 安装时,在这些文件中出现了一些错误:unclosed character literalillegal character: '\u00a8'。使用编码为 UTF8 的插件进行安装时:

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.3.2</version>
        <configuration>
            <source>1.8</source>
            <target>1.8</target>
            <encoding>UTF-8</encoding>
        </configuration>
    </plugin>

错误不再显示在上述文件中,但在许多其他文件中,显示的错误是:unmappable character for encoding UTF-8.

我可以只为某些文件指定 UTF-8 编码吗?


另外,maven显示错误如下:

folder/file.java:[10,19] unclosed character literal
folder/file.java:[10,22] unclosed character literal
folder/file.java:[13,19] unclosed character literal

数字是什么意思?好像不是错误所在的行号。

[10,19]表示:第10行第19个字符。

@VGR 准确解释了为什么以 CP1252 读取 UTF-8 编码的源文件会导致编译失败:任何 non-ASCII 字符在 UTF-8 中至少编码为 2 个字节。如果您随后错误地将这些字节读取为 Cp1252,您将获得 2 个或更多官方字符。考虑到 char 文字只允许内部有 1 个字符,代码现在有编译器错误。

没有办法告诉 maven 一些文件是 UTF-8 而一些文件是 Cp1252,除非你 运行 单独编译 运行s,这很难做到,会非常混乱和很难维护(所以,一个坏主意),并且根本无法工作,除非你涉及存根或者你是 'lucky' 并且两批中的一个是 'self contained' (绝对不包含对来自另一个 'batch').

的任何东西

所以让我们把它作为可行的选择去掉。剩下 2 个选项:

正确的选择 - 所有时间都是 UTF-8

将所有源文件视为 UTF-8。这比听起来容易;所有 ASCII 字符在 UTF-8 和 Cp1252 中的编码相同,因此只有 non-ASCII 个字符需要检查。这很容易找到:它实际上是 126 以上的所有字节。您可以使用许多工具来找到它们。 Here is an SO question with answers 关于如何在 linux 上执行此操作。

使用任何编辑器打开这些文件,清楚地表明它使用的是哪种编码(大多数开发人员编辑器都是正确的),重新加载编码直到这个字符看起来正确,然后 re-save 为 UTF-8,瞧.所有没有特殊字符的同时都是 UTF-8 和 Cp1252 - 你可以简单地使用 UTF-8 编码编译它们,它就可以正常工作。

现在您的所有代码都在 UTF_8 中。相应地配置您的 IDE 项目/只需将您的 maven pom 保留在 'it is UTF-8' 上,所有 maven-aware 项目工具将自动使用它。

更糟糕的选择 - backslash-u 转义

如果你不能那样做,因为一些工具读取那些源文件(不是 maven 和 javac,实际上几乎没有来自 java 生态系统的主要内容,因为 java 生态系统都非常了解 UTF-8)并且只是坚持将其解析为 Cp1252,对此您无能为力:有一种方法可以从源文件中删除所有 non-ASCII:backslash-u 转义。

概念 \u0123 在任何 java 文件中的任何地方都是合法的,而不仅仅是在字符串文字中。这意味着:具有该值的 unicode 字符(十六进制)。例如,这个:

class Test {
  public static void main(String[] args) {
    //This does nothing, right? \u000aSystem.out.println("Hello!");
  }
}

当您 运行 它时, 实际上会打印 Hello!。即使系统输出在评论中......还是?

\u000a 是换行符。所以,上面的文件被解析为一行注释,然后是换行符,所以 System.out 语句确实在那里,而不是在注释中。许多工具不知道这一点(例如 sublime text 和 co 将以注释绿色呈现该 sysout 语句),但 javac 并且,事实上,Java Lang Spec 是 crystal 明确的this: 上面的代码里面有一个真正的打印语句,没有被注释掉。

因此,您可以寻找所有 non-ASCII 并将其替换为 u 转义符,现在您的代码是混合的:无论您使用哪种编码,只要它是 ASCII 兼容编码,它的解析都是相同的, 并且几乎所有的编码都是(只有少数日文和其他东亚字符集,以及 UTF-16/UCS2/UCS4/UTF-32 风格的编码,是 non-ASCII 兼容的。Cp1252,Iso- 8859、UTF_8 本身、ASCII 本身、Cp850 和许多其他 'ASCII compatible',意思是,100% ASCII 文本由所有这些编码进行相同编码)。

要将事情变成u转义,在任何unicode网站上查找该符号的十六进制值并应用它。例如,é 变为 \u00E9(参见 é) and ☃ becomes \u2603 (see unicode snowman)。

将这些转义符放在 where-ever 你在源文件中看到 non-ascii,即使你在字符串文字之外看到它:

合法java:

public class Fighter {
  public void mêléeAttack() {}
}

但是.. 如果您混淆了编辑器中的编码设置和 maven 中的编码设置,那就太糟糕了。然而,这:

public class Fighter {
  public void m\u00EAl\u00E9eeAttack() {}
}

意思是一样的,即使你弄乱了编码也能正常工作。它在您的编辑器中看起来真的很糟糕,这就是为什么这是一个相当糟糕的选择。