awk tolower 以重音符开头的字符串 - 支持外来字符

Awk tolower a string that starts with an accent - support for foreign characters

我有一个文件,其中一行包含此字符串:"Ávila"

我想得到这个输出:"ávila".

问题是awk的tolower函数只有在字符串不以accent开头的情况下才有效,我必须用awk。

例如,如果我执行 awk 'BEGIN { print tolower("Ávila") }',那么我会得到 "Ávila" 而不是 “ávila”,这正是我所期望的。

但是如果我执行 awk 'BEGIN { print tolower("Castellón") }' 那么我会得到 "castellón"

对于给定的 awk 实现,要正确处理非 ASCII 字符(外来字母),它必须遵守活动语言环境的字符编码,如(有效)LC_CTYPE 设置( 运行 locale 看看吧)。

如今,大多数语言环境都使用 UTF-8 编码,这是一种多字节按需编码,在 ASCII 范围内是单字节,并使用 2 到 4 个字节来表示所有其他 Unicode 字符。
因此,对于给定的 awk 实现来识别非 ASCII(重音,外语)字母,它必须能够将 多个字节 识别为 单个字符.

在主要 awk 实现中,

  • GNU Awk (gawk),some Linux distros
  • 上的默认设置
  • BSD awk,也用于 OS X
  • Mawk (mawk),基于 Debian 的 Linux 发行版的默认设置,例如 Ubuntu

GNU Awk 正确处理 UTF8 编码的字符(如果在语言环境中指定,则可能是任何其他编码):

$ echo ÁvilA | gawk '{print tolower([=10=])}'
ávila  # both Á and A lowercased

相反,如果您明确希望将字符处理限制为仅使用 ASCII,请在前面添加 LC_CTYPE=C:

$ echo ÁvilA | LC_CTYPE=C gawk '{print tolower([=11=])}'
Ávila  # only ASCII char. A lowercased

实用建议:

  • 确定您的默认 awk 是什么实现, 运行 awk --version.

    • 在 Mawk 的情况下,您会收到一条错误消息,因为它仅支持使用 -W version 打印版本信息,但该错误消息将包含单词 mawk.
  • If 可能,安装并使用 GNU Awk(并可选择将其设为默认 awk);它适用于大多数类 Unix 平台;例如:

    • 在基于 Debian 的平台上,例如 Ubuntu:sudo apt-get install gawk
    • 在 OS X 上,使用 Homebrewbrew install gawk
  • 如果您必须使用 BSD Awk 或 Mawk,请使用上述 LC_CTYPE=C 方法 确保多byte UTF-8字符至少通过不加修改[1],但外来字母不会被识别为字母(因此在这种情况下不会小写)。


[1] OS X 上的 BSD Awk 和 Mawk(奇怪的是后者 而不是 Linux 上的 )按如下方式处理 UTF-8 编码字符:

  • 每个字节被错误地解释为它自己的字符
  • 如果,忽略高位后,得到的字节值落在ASCII大写字母范围内,32加入原始 字节值以获得对应的小写字母。

在手头的例子中,这意味着:

  • Á是Unicode代码点U+00C1,其UTF-8编码是2字节序列0xC3 0x81.

  • 0xC3:删除高位 (0xC3 & 0x7F) 产生 0x43,它被解释为 ASCII 字母 C,而 32 (0x20) 因此被添加到 原始值 ,产生 0xE3 (0xC3 + 0x20).

  • 0x81:删除高位 (0x81 & 0x7F) 得到 0x1,它不在 ASCII 大写字母范围内 (65-90 , 0x41-0x5a), 所以字节保持原样。

  • 实际上,第一个字节由0xC3修改为0xE3,而第二个字节保持不变;由于 0xC3 0x81 不是 正确的 UTF-8 编码字符,终端将打印 ? 而不是发出信号。

我试着对你的回复发表评论,这是正确的,但我需要能够格式化我添加的内容,否则,它会变得乱码。

超级有用,我想为那些有大写问题的人添加以下内容:

bash-3.2$ echo "TOMÀS VICENÇ ROMÀ" |LC_CTYPE=C gawk '{ print tolower([=10=])}'

tomÀs vicenÇ romÀ


bash-3.2$ echo "TOMÀS VICENÇ ROMÀ" |LC_CTYPE=C gawk '{ print [=10=]}'|tr '[:upper:]' '[:lower:]'

tomàs vicenç romà