对用户输入和文件-reader 输入实施编码标准化

enforce standardization of encoding for user input & file-reader input

我正在设计一个系统来确定给定文本的人类语言。它的工作原理是为每种感兴趣的语言存储一个字典,然后评估用户输入是否与字典中存储的任何单词相对应。词典点击次数最多的语言获胜。

我猜为了让这两个条目,用户的单词和来自“单词列表”文件的单词匹配编码必须相同,这就是我要解决的问题。

我从 this site 中获取了单词列表。

当我在我的代码中使用来自“ASCII”的代码时,一切正常,但是当我使用来自“Unicode”的代码时没有任何作用。

这让我感到不安,因为我不希望程序获得一些以错误方式编码的输入(以一种与我的单词列表数据结构冲突的方式)然后失败。

出于这个原因,我想用特定的编码来标准化所有输入。我当时认为“Unicode”会更好,因为这是一个用于确定文本自然语言的系统,我可能会得到一些希腊语、俄语或中文字符,根据我的理解“ASCII”是高度非标准化的。

我目前正在使用Eclipse的控制台来编写输入。

这是我读取文件的方式:

//BufferedReader br = new BufferedReader( new InputStreamReader(new FileInputStream( dir.toString() ), "UTF-8") );

BufferedReader br = new BufferedReader( new FileReader( dir.toString() ) );
String line = null;

BloomFilter<String> bloomFilter;
if (word_holding_directory_path.toLowerCase().contains("/de/")) 
{
    bloomFilter = de_bloomFilter;
} 

我是这样读用户输入的:

//Scanner in = new Scanner( System.in , "UTF-8");
Scanner in = new Scanner(System.in);

System.out.println("Please enter a sentence: ");

String[] input_text = in.nextLine().split("\s");

如您所见,我试图强制编码为 UTF-8(这与 Unicode 是一回事,不是吗?),但由于它不起作用,我将其注释掉了。

我是这样比较词的:

for (String word : input_text) 
{
    String normalized = word.trim().toLowerCase();
    if (words.contains(normalized)) 
    {
        ++count;
    }
}

完整的程序是 here on github,它很短,而且注释相当明确。

您 link 的词典似乎是 UTF-16LE,而不是 UTF-8。您应该相应地修复 InputStreamReader 实例化中的编码参数。

Unicode 和 UTF-8 最强调不是同一事物;事实上,说文本是 "Unicode" 而不提及编码是不够精确的。1

(您应该能够猜到,几年前的 ZIP 文件可能使用 UTF-16LE,对于许多事情,这仍然是 Windows 上的默认值。新资源通常是 UTF-8 , 即使在 Windows.)

从 UTF-16 文件中读取一个字符串,并从控制台读取包含相同文本且控制台编码正确的另一个字符串,将生成两个相等的 Java 字符串。另一方面,如果其中一个输入流的编码不正确,那么您最终在字符串中得到的内容基本上是随机伪造的。 (在 "train wreck" 场景中,两个输入都有不同的编码错误,只是巧合地得到两个相等的字符串,而实际上这两个字符串应该包含不同的文本。)

(不确定 UTF-8 是否普遍适用于控制台,或者是否特别适用于您的环境——我不是 Java 程序员。)


1 简而言之,抽象 Unicode 字符串

U+0066 U+00F6 U+0072

(表示瑞典语单词 för) 将表示为

0x66 0xC3 0xB7 0x72

在 UTF-8 中(注意纯 ASCII 字符如何映射到身份表示),以及

0x66 0x00 0xF6 0x00 0x72 0x00

在 UTF-16LE 中(其中每对字节是一个 16 位序列,MSB 设置为零,而 LSB 包含表示的整个重要部分)。

在纯ASCII中,无法表示该字符串;回到过去,它会被写成

0x66 0x7C 0x72

其中 0x7C 是正确的管道字符 |,它在硬件中本地映射到字形 ö。 (相应地,如果您使用的英文资源应该包含适当的竖线字符,那么它也将呈现为 ö;因此 Unix 管道线 grep cat food | xxd 将显示为 grep cat food ö xxd.)

不久之后,ISO-8859-1 开始流行,这个字符串将表示为

0x66 0xFC 0x72

这当然简单高效。为什么 Unicode 也不是这样表示的?因为 8 位编码只有 256 个字符,而 Unicode 要大得多。你根本不能代表上海市машина