- 上下文
- 发现了问题
- 问题编号1
- 问题编号2
- 问题编号3
- 问题
上下文
今天,我想保留包含汉字的文件中的唯一行。我决定使用该sort
实用程序,因为我熟悉该工具,并且删除文件中的重复行就像使用该-u
标志一样简单。我了解到我需要更改区域设置才能sort
正确使用中文字符。我注意到使用不同的区域设置sort
会有不同的行为。在这篇文章中,我展示了我的发现。
我知道删除文件中重复行的任务可以使用多种工具/编程语言来完成。虽然我感谢任何建议完成该任务的工具的人,但我更感兴趣的是了解有关语言环境以及它们如何影响 Unix 实用程序的更多信息。
发现了问题
问题编号1
以下是我的系统的区域设置。
locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
考虑以下名为main.txt
䔍
䏝
如果我尝试使用en_US.UTF-8
as my对其进行排序$LANG
。我失去了行号。 2
sort -u main.txt
䔍
LANG
我已经通过设置解决了这个问题zh_CN.UTF-8
。
export LANG=zh_CN.UTF-8
sort -u main.txt
䔍
䏝
我创建一个问题关于 Stack Overflow 中的这个问题。有人建议我更改语言环境,它似乎有效,我以为我已经解决了问题,但后来我发现问题没有。 2 和问题编号。 3(如下所述)。
问题编号2
现在,假设我们在文件中添加两行main.txt
䔍
䏝
答案1
sort -u
输出在区域设置中整理相同(具有相同排序顺序)的每组行之一。
在 GNU 系统(使用 GNU libc 的系统)上,在大多数语言环境中,许多字符 1 具有未定义的排序顺序,这意味着它们最终排序相同,并且还存在显式定义为具有相同排序顺序的字符。
当字节无法解码为文本时,它们通常也会被忽略或被认为具有相同的排序顺序²。
因此,为了sort -u
给您基于字节到字节相等比较的独特行,无论文本使用何种编码编写,您都需要一个区域设置,其中每个字节都可以解码为一个字符和一个具有总顺序的区域设置。
最简单的方法是使用C
有一个字节 == 一个字符映射的区域设置(某些字节可能导致不明确的字符),排序基于字节值(至少在基于 ASCII 的系统上),并且是您保证在任何给定系统上找到的唯一区域设置。
就您的情况而言,要了解为什么zh_CN
会给您带来更好的行为,您可以查看通常在/usr/share/i18n/locale
GNU 系统上的语言环境定义zh_CN
,您可以在其中找到:
LC_COLLATE
copy "iso14651_t1_pinyin"
END LC_COLLATE
哪里iso14651_t1_pinyin
有:
copy "iso14651_t1_common"
然后指定许多附加汉字的排序,而en_US
仅使用iso14651_t1_common
.
如果您设置LC_CTYPE
(通过LANG
)为 zh_CN.GB18030 或 zh_CN.GBK 并尝试处理以 UTF-8 编码的文件,sort
通常无法将行解码为文本,因为 UTF-8 编码文本的字节通常不形成有效的形式GB18030 编码的文本会让问题变得更糟。
在这里,如果您想获得唯一的(根据字节到字节比较)行,但也想在您的语言环境中获得“正确”排序的输出,您可以这样做:
LC_ALL=C sort -u your-file | sort
第一个sort
删除重复项,第二个根据您的区域设置排序规则对剩余行进行排序。
我们使用LC_ALL
而不是LANG
or LC_CTYPE
+ ,LC_COLLATE
因为这是覆盖所有内容的变量(LC_ALL
优先于LC_individual_setting
which 优先于LANG
),所以如果LANG
orLC_COLLATE
也以其他方式在环境中设置,它仍然有效。
理论上,你还可以这样做:
LC_ALL= LC_CTYPE=C LC_COLLATE=C sort
以便仅设置“字符类型”和“排序规则”设置,而单独保留其他区域设置类别(由LANG
或覆盖LC_xxx
),但 所使用的其余类别sort
用于LC_MESSAGES
例如错误消息,如果您设置LC_CTYPE=C
,则仅使用 US-无论如何,英语消息都可以正确显示,因为它只有 ASCII 字符。例如:
$ LC_MESSAGES=zh_CN LC_CTYPE=C sort --version
sort (GNU coreutils) 9.1
Copyright (C) 2022 Free Software Foundation, Inc.
??? GPLv3+:GNU ???????? 3 ?????? <https://gnu.org/licenses/gpl.html>?
????????:??????????????
?????????,????????
? Mike Haertel ? Paul Eggert ???
您可以在以下位置找到更多详细信息:
严格来说,主要单位不是特点但整理元素它可以由多个类似的字符组成, ch
例如在某些捷克地区之间h
或i
在某些捷克地区中。
² 请注意,某些sort
实现(非 GNU sort
)也会因 NUL 字符或过长的行而阻塞。