Java 用ASCII替换Unicode

Java 用ASCII替换Unicode,java,string,encoding,character-encoding,Java,String,Encoding,Character Encoding,我在windows系统上创建了一个文本文件,默认编码样式为ANSI,文件内容如下: This is\u2019 a sample text file \u2014and it can .... 我使用windows的默认编码样式保存了这个文件,不过也有一些编码样式,如UTF-8、UTF-16等 现在我想编写一个简单的java函数,在这里我将传递一些输入字符串,并用相应的ascii值替换所有Unicode e、 g:-\u2019应替换为“” \u2014应替换为“-”等。 观察: 当我创建这样

我在windows系统上创建了一个文本文件,默认编码样式为ANSI,文件内容如下:

This is\u2019 a sample text file \u2014and it can ....
我使用windows的默认编码样式保存了这个文件,不过也有一些编码样式,如UTF-8、UTF-16等

现在我想编写一个简单的java函数,在这里我将传递一些输入字符串,并用相应的ascii值替换所有Unicode

e、 g:-
\u2019应替换为“”
\u2014应替换为“-”等。

观察: 当我创建这样的字符串文字时

  String s = "This is\u2019 a sample text file \u2014and it can ....";
我的代码工作正常,但当我从文件中读取代码时,它不工作。我知道Java中的字符串使用UTF-16编码

下面是我用来读取输入文件的代码

FileReader fileReader  = new FileReader(new File("C:\\input.txt"));
BufferedReader bufferedReader = new BufferedReader(fileReader)
String record = bufferedReader.readLine();
我还尝试使用
输入流并将字符集设置为UTF-8
,但结果仍然相同

更换代码:

public static String removeUTFCharacters(String data){      
        for(Entry<String,String> entry : utfChars.entrySet()){
            data=data.replaceAll(entry.getKey(), entry.getValue());
        }
        return data;
    }
    utfChars.put("\u2019","'");
    utfChars.put("\u2018","'");
    utfChars.put("\u201c","\"");
    utfChars.put("\u201d","\"");
    utfChars.put("\u2013","-");
    utfChars.put("\u2014","-");
    utfChars.put("\u2212","-");
    utfChars.put("\u2022","*");

有人能帮我理解这个问题的概念和解决方案吗。

用正则表达式匹配转义序列\uxxx。然后使用替换循环将该转义序列的每次出现替换为该字符的解码值

因为Java字符串文字使用
\
来引入转义,所以序列
\\
用于表示
\
。另外,Java正则表达式语法专门处理序列
\u
(表示Unicode转义)。因此,必须再次转义
\
,并附加
\
。因此,在模式中,
“\\\\u”
实际上意味着“匹配输入中的
\u

要匹配数字部分(四个十六进制字符),请使用模式
\p{XDigit}
,用额外的
\
\
进行转义。我们希望很容易地将十六进制数提取为一个组,因此将其括在括号中以创建一个捕获组。因此,模式中的“
”(\\p{XDigit}{4})”
意味着“匹配输入中的4个十六进制字符,并捕获它们。”

在循环中,我们搜索模式的出现,用解码的字符值替换每个出现。通过解析十六进制数对字符值进行解码
Integer.parseInt(m.group(1),16)
的意思是“将上一个匹配中捕获的组解析为base-16数字。”然后用该字符创建替换字符串。如果替换字符串是
$
,则必须对其进行转义或引用,这在替换文本中具有特殊意义

String data = "This is\\u2019 a sample text file \\u2014and it can ...";
Pattern p = Pattern.compile("\\\\u(\\p{XDigit}{4})");
Matcher m = p.matcher(data);
StringBuffer buf = new StringBuffer(data.length());
while (m.find()) {
  String ch = String.valueOf((char) Integer.parseInt(m.group(1), 16));
  m.appendReplacement(buf, Matcher.quoteReplacement(ch));
}
m.appendTail(buf);
System.out.println(buf);

如果您可以使用另一个库,那么就可以使用ApacheCommons


我想澄清一下,你是说你的文件中有六个字符,分别是
'\'
'u'
'2'
'0'
'1'
'9'
?在现实世界中,我将从一些外部系统收到这个文件,他们告诉我你将收到这些Unicode,比如“\u2019”在输入文本文件中。出于单元测试的目的,我尝试创建与我将要接收的文件类型相同的文件。您能告诉我们在阅读后,
字符串
中实际显示了哪些16位字符吗?类似于(i=0;它是这样显示的-0054 0068 0069 0073 0020 0069 0073 005C 005C 0075 0032 0030 0031 0039 0020 0061 0020 0061 006D 0070 006C 0065 0020 0074 0065 0078 0074 0020 0066 0069 006C 0065 0020 005C 0075 0032 0031 0034 0061 0064 0020 0069 0074 0020 0063 0061 0061 002E 002E 002E 002E 002E 002E 002E 002E 002E 002E 002E 002E 002E 002谢谢,它起作用了。这将是非常重要的lp如果你能解释一下背景中到底发生了什么。@Saurav注意,我做了一个小改动来修复序列\u0024(
$
)时的一个bug是在输入中找到的。我将对示例进行注释以解释发生了什么。还有一件事,如果在保存文件时将文件的编码样式从默认更改为UTF-8或UTF-16,会有什么影响。@Saurav我也没有正确处理十六进制,所以也要注意这个更改。当您创建
读取器时,您应该使用一个
InputStreamReader
,并将编码指定为用于保存文件的任何编码。现在,您正在使用系统默认编码来读取文件,因此如果您使用不同的编码编写文件,它可能会中断。但是,我猜在输入文件中使用转义序列的全部目的是使它们可以用US-ASCII编码;也就是说,它们不应该包含“特殊”字符,对吗?是的,对我来说很有意义。非常感谢你的简明解释。你的例子激励我学习正则表达式。
String dirtyString = "Colocaci\u00F3n";
String cleanString = StringEscapeUtils.unescapeJava(dirtyString);
//cleanString = "Colocación"