当前位置: 首页 > 面试题库 >

语言环境如何在Linux / POSIX中工作,并且应用了哪些转换?

翟英达
2023-03-14
问题内容

我正在处理(我希望)UTF-8文本巨大的文件。我可以使用Ubuntu 13.10(3.11.0-14-generic)和12.04复制它。

在调查错误时,我遇到了奇怪的行为

$ export LC_ALL=en_US.UTF-8   
$ sort part-r-00000 | uniq -d 
ɥ ɨ ɞ ɧ 251
ɨ ɡ ɞ ɭ ɯ       291
ɢ ɫ ɬ ɜ 301
ɪ ɳ     475
ʈ ʂ     565

$ export LC_ALL=C
$ sort part-r-00000 | uniq -d 
$ # no duplicates found

当运行使用来读取文件的自定义C
++程序时,重复项也会出现 std::stringstream-由于使用 en_US.UTF-8区域设置时重复项而导致失败。

至少对于std::string输入和输出,C ++似乎并不受影响。

为什么在使用UTF-8语言环境时发现重复项,而在C语言环境中找不到重复项?

语言环境对导致此行为的文本进行了哪些转换?

编辑:这是一个小例子

$ uniq -D duplicates.small.nfc 
ɢ ɦ ɟ ɧ ɹ       224
ɬ ɨ ɜ ɪ ɟ       224
ɥ ɨ ɞ ɧ 251
ɯ ɭ ɱ ɪ 251
ɨ ɡ ɞ ɭ ɯ       291
ɬ ɨ ɢ ɦ ɟ       291
ɢ ɫ ɬ ɜ 301
ɧ ɤ ɭ ɪ 301
ɹ ɣ ɫ ɬ 301
ɪ ɳ     475
ͳ ͽ     475
ʈ ʂ     565
ˈ ϡ     565

locale问题出现时的输出:

$ locale 
LANG=en_US.UTF-8                                                                                                                                                                                               
LC_CTYPE="en_US.UTF-8"                                                                                                                                                                                         
LC_NUMERIC=de_DE.UTF-8                                                                                                                                                                                         
LC_TIME=de_DE.UTF-8                                                                                                                                                                                            
LC_COLLATE="en_US.UTF-8"                                                                                                                                                                                       
LC_MONETARY=de_DE.UTF-8                                                                                                                                                                                        
LC_MESSAGES="en_US.UTF-8"                                                                                                                                                                                      
LC_PAPER=de_DE.UTF-8                                                                                                                                                                                           
LC_NAME=de_DE.UTF-8                                                                                                                                                                                            
LC_ADDRESS=de_DE.UTF-8                                                                                                                                                                                         
LC_TELEPHONE=de_DE.UTF-8                                                                                                                                                                                       
LC_MEASUREMENT=de_DE.UTF-8                                                                                                                                                                                     
LC_IDENTIFICATION=de_DE.UTF-8                                                                                                                                                                                  
LC_ALL=

编辑:规范化后使用:

cat duplicates | uconv -f utf8 -t utf8 -x nfc > duplicates.nfc

我仍然得到相同的结果

编辑:文件根据iconv-(从此处开始)是有效的UTF-8

$ iconv -f UTF-8 duplicates -o /dev/null
$ echo $?
0

编辑:看起来与此类似:http :
//xahlee.info/comp/unix_uniq_unicode_bug.html
和 https://lists.gnu.org/archive/html/bug-
coreutils/2012-07/msg00072.html

它在FreeBSD上工作


问题答案:

我将问题归结为strcoll()函数问题,该问题与Unicode规范化无关。回顾:我的最小示例展示了uniq依赖当前语言环境的不同行为:

$ echo -e "\xc9\xa2\n\xc9\xac" > test.txt
$ cat test.txt
ɢ
ɬ
$ LC_COLLATE=C uniq -D test.txt
$ LC_COLLATE=en_US.UTF-8 uniq -D test.txt
ɢ
ɬ

显然,如果语言环境是en_US.UTF-8
uniq对待ɢɬ作为重复项,则情况并非如此。然后,我再次使用运行相同的命令,valgrind并使用来调查了两个调用图kcachegrind

$ LC_COLLATE=C valgrind --tool=callgrind uniq -D test.txt
$ LC_COLLATE=en_US.UTF-8 valgrind --tool=callgrind uniq -D test.txt
$ kcachegrind callgrind.out.5754 &
$ kcachegrind callgrind.out.5763 &

唯一的区别是,与该版本LC_COLLATE=en_US.UTF-8名为strcoll()LC_COLLATE=C没有这样做。因此,我提出了以下最小示例strcoll()

#include <iostream>
#include <cstring>
#include <clocale>

int main()
{
    const char* s1 = "\xc9\xa2";
    const char* s2 = "\xc9\xac";
    std::cout << s1 << std::endl;
    std::cout << s2 << std::endl;

    std::setlocale(LC_COLLATE, "en_US.UTF-8");
    std::cout << std::strcoll(s1, s2) << std::endl;
    std::cout << std::strcmp(s1, s2) << std::endl;

    std::setlocale(LC_COLLATE, "C");
    std::cout << std::strcoll(s1, s2) << std::endl;
    std::cout << std::strcmp(s1, s2) << std::endl;

    std::cout << std::endl;

    s1 = "\xa2";
    s2 = "\xac";
    std::cout << s1 << std::endl;
    std::cout << s2 << std::endl;

    std::setlocale(LC_COLLATE, "en_US.UTF-8");
    std::cout << std::strcoll(s1, s2) << std::endl;
    std::cout << std::strcmp(s1, s2) << std::endl;

    std::setlocale(LC_COLLATE, "C");
    std::cout << std::strcoll(s1, s2) << std::endl;
    std::cout << std::strcmp(s1, s2) << std::endl;
}

输出:

ɢ
ɬ
0
-1
-10
-1

�
�
0
-1
-10
-1

那么,这怎么了?为什么对两个不同的字符strcoll()返回0(等于)?



 类似资料:
  • 我有以下问题: 我想以编程方式更改我的应用程序的语言。 所以我使用共享首选项来更改语言环境。 b0是保存的本地。 b0与德语语言环境de和英语语言环境en完美配合,但与美国语言环境en\U US却没有配合 当然,我添加了一个新文件夹: 使用美国字符串xml。 如果我将手机语言更改为英语(美国),应用程序将以美国英语开始。 我甚至编辑了我的台词: 仍然不工作。 “en\u US”有什么问题吗? ht

  • 问题内容: 我有一个Action类,我想获取应用程序的语言环境并在此处进行更改,但是我不知道怎么做,也找不到答案。 我可以使用获取当前的语言环境 但是我不知道如何 设置语言环境 。 我想在上述Action类中直接为我的应用更改语言环境。我怎样才能做到这一点? 问题答案: 使用和将其放在HTTP会话中 。

  • 问题内容: 我在指定语言代码的应用程序中读取了一个文件: 必须采用以下格式:例如 en_UK,en_US等。是否可以在继续之前验证语言环境字符串是否有效? 问题答案: 现在我要做: 效果很好。

  • 在我的应用程序中,用户应该能够切换区域设置(用于在页面上呈现文本的语言)。大量教程使用FacesContext.get货币实例()。getViewRoot()。setLocale()。例如:http://www.mkyong.com/jsf2/jsf-2-internationalization-example/.但是,这在JSF 2.0中根本不起作用(它在1.2中确实起作用)。这种语言从不切换。

  • 变量是计算机系统用于保存可变值的数据类型,我们可以直接通过变量名称来提取到对应的变量值。在 Linux 系统中,环境变量是用来定义系统运行环境的一些参数,比如每个用户不同的家目录(HOME)、邮件存放位置(MAIL)等。 值得一提的是,Linux 系统中环境变量的名称一般都是大写的,这是一种约定俗成的规范。 我们可以使用 env 命令来查看到 Linux 系统中所有的环境变量,执行命令如下: [r

  • 问题内容: 我有一个Spring应用程序,希望用户能够更改首选语言环境。当前,用户可以更改当前会话的语言环境,但是我希望能够保存users选项,以便每当他们登录时,使用已保存的语言环境(如果存在)。我有一个mysql数据库,用于存储用户区域设置首选项。我创建了一个自定义AuthenticationSuccessHandler,以处理将语言环境更改为已保存的语言环境的操作,该方法适用于已将语言环境保