【问题标题】:Keep unicode characters in Java string在 Java 字符串中保留 unicode 字符
【发布时间】:2015-06-15 20:48:18
【问题描述】:

我正在用java编写一个爬虫来爬取一些网站,这些网站可能有一些unicode字符,比如“£”。当我将内容(源 HTML)存储在 Java 字符串中时,这些类型的字符会丢失并被问号“?”替换。我想知道如何保持它们完好无损。相关代码如下:

protected String readWebPage(String weburl) throws IOException{
        HttpClient httpclient = new DefaultHttpClient();

        HttpGet httpget = new HttpGet(weburl); 
        ResponseHandler<String> responseHandler = new BasicResponseHandler();    
        String responseBody = httpclient.execute(httpget, responseHandler);
        // responseBody now contains the contents of the page
        httpclient.getConnectionManager().shutdown();
        return responseBody;
    }

   // function call
   String res = readWebPage(url);
   PrintWriter out = new PrintWriter(outDir+name+".html");
   out.println(res);
   out.close();

稍后在进行字符匹配时,我还希望能够执行以下操作:

if(text.indexOf("£")>=0)

我不知道 Java 是否会识别该字符并按照我的意愿去做。

任何意见将不胜感激。提前致谢。

【问题讨论】:

    标签: java string unicode utf-8 character


    【解决方案1】:

    您的非 ASCII 字符要么在输入到 Java 时丢失,要么在输出时丢失。

    Java 在内部使用 Unicode 字符串,因此您必须告诉它如何解码输入和编码输出。

    假设HttpClient 正确解释来自远程服务器的响应并且正确解码响应。

    接下来,您必须确保在将内容写入磁盘时对其进行正确编码。 Java使用本地环境变量来猜测使用什么编码,这可能不合适。要强制编码,请将编码类型传递给 PrintWriter:

    PrintWriter out = new PrintWriter(outDir+name+".html", "UTF-8");
    

    然后使用以 UTF-8 模式运行的文本编辑器(例如 Notepad++)检查您的 output.html,以确保您仍然可以看到非 ASCII 字符。

    如果你不能,那么你需要将注意力转向输入 - HttpClient。如果您的远程服务器在字符编码方面撒谎,请参阅此答案:Set response encoding with HttpClient 3.1

    回答您的子问题。如果你告诉 Java 你的源代码是什么字符编码,你可以在你的源代码中使用非 ASCII 字符,例如“£”。这是javac 的一个参数,但你可能使用的是 IDE ,您可以简单地在属性中设置文件的字符编码,其余的由 IDE 完成。最便携的做法是将 IDE 中的字符编码设置为“UTF-8”。 Eclipse 允许您为整个项目或单个文件设置字符编码。

    【讨论】:

      【解决方案2】:

      使用以下代码:

      FileOutputStream fileStream = new FileOutputStream(outDir+name+".html");
      OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileStream, StandardCharsets.UTF_8)
      PrintWriter out = new PrintWriter(outputStreamWriter);
      

      来自Charset

      字符编码方案是一个或多个编码字符集与一组八位字节(八位字节)序列之间的映射。 UTF-8、UTF-16、ISO 2022 和 EUC 是字符编码方案的示例。编码方案通常与特定的编码字符集相关联;例如,UTF-8 仅用于编码 Unicode。然而,一些方案与多个编码字符集相关联;例如,EUC 可用于对各种亚洲编码字符集中的字符进行编码。

      【讨论】:

      • 感谢您的回答。它对我有用。但是你能给出一些解释吗?因此,从服务器读取页面时,Unicode 字符实际上完好无损地保存在 String res 中,但在将其写入硬盘驱动器中的文件时会丢失?你知道为什么第二个块中的代码有效吗?我将 unicode char 直接复制到源代码中以进行正则表达式匹配。只是想知道它在幕后是如何工作的。非常感谢。
      • @JFreebird 查看答案。
      【解决方案3】:

      有两个步骤。首先,将加载的字符串(在 java 中始终为 Unicode)保存为 UTF-8。但是由于浏览器需要知道编码,它只有文件系统上的 HTML 元标记。所以你需要确定,有类似的东西

      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      

      2. 使用 UTF-8 编写 HTML

      PrintWriter out = new PrintWriter(outDir+name+".html", "UTF-8");
      

      1.先将原始页面的HTML字符集声明打补丁成UTF-8。

      String res2 = res.replaceFirst("charset=([-\\w]+)", "charset=UTF-8")
               .replaceFirst("charset=([\"'])([-\\w]+)\1", "charset=$1UTF-8$1");
      if (res2 == res) { // No charset given
            res2 = res.replaceFirst("(?i)</head>",
                    "<meta http-equiv='Content-Type' content='text/html; charset=UTF-8' />$0");
      }
      res = res2;
      

      对于具有 Content-Type 或 (HTML5) 字符集的 HTML 元数据。

      【讨论】:

      • 第二种解决方案似乎更容易......你知道我是否可以直接在java源代码中编写unicode字符来进行正则表达式匹配吗?谢谢。
      • 我添加了一个解释,以使神秘代码的目的更加清晰。
      • @tchrist yes char 是 UTF-16 /两个字节),而 String 由 chars 组成。 .class 文件中的字符串常量存储为 UTF-8。在引入 Java 时,选择 String 存储完整的 Unicode,我对这个明智的决定表示敬意。
      • 这不太对。 UTF-16 是一种可变宽度编码,就像 UTF-8 一样。这不是“两口子”。 UTF-8、UTF-16 和 UTF-32 这三个都可以存储“完整的 Unicode”,但是太多的 Java 程序员会误以为 Java 字符是 Unicode,或者它是 UTF-16,而这些是错误的。他们将 UTF-16 视为 UCS-2,这会导致无穷无尽的错误。 C#程序员也是如此。 Windows 程序员也是如此。一团糟。此外,Java 字符串可以保存非 Unicode,因为它没有将逻辑字符与物理字节或字符分开。
      • @tchrist "two bytes" 引用 char I appreciate the rant; same feelings on Unicode out there. Though String should never contain binary data. There is a conceptual difference between (Unicode) text (String, char, Reader/Writer) amd binary data (byte[], Input- and OutputStream). char` 很尴尬,java-8 支持更多的代码点(UTF-32),但即便如此,它也是一个有效的 Unicode 符号/character 可能由几个代码点组成。但是,是的,那里的滥用是巨大的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-09
      • 1970-01-01
      • 2019-05-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多