【问题标题】:Awk tolower a string that starts with an accent - support for foreign charactersawk 降低以重音开头的字符串 - 支持外来字符
【发布时间】:2016-08-30 06:15:52
【问题描述】:

我有一个包含此字符串的文件:"Ávila"

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

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

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

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

【问题讨论】:

  • 使用 gnu awk 4.0.1 我从 tolower("Ávila") 得到“ávila”。
  • 顺便说一句:问题与字符串中外来字符的 位置 无关(在您的第二个命令中,外来字母恰好已经是小写了),但是在某些 awk 实现中根本无法将非 ASCII 字母识别为字母。

标签: awk character-encoding diacritics


【解决方案1】:

要使给定的awk 实现与非 ASCII 字符(外来字母)正常工作,它必须尊重活动区域设置的字符编码,如(有效)LC_CTYPE 设置(运行locale 以查看它)。

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

在主要的awk 实现中

  • GNU Awk (gawk),一些 Linux 发行版的默认设置
  • BSD awk,也用于 OS X
  • Mawk (mawk),Ubuntu 等基于 Debian 的 Linux 发行版的默认设置

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

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

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

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

实用建议:

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

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

    • 在基于 Debian 的平台上,例如 Ubuntu:sudo apt-get install gawk
    • 在 OS X 上,使用 Homebrew: brew install gawk
  • 如果必须使用 BSD Awk 或 Mawk,请使用上述 LC_CTYPE=C 方法确保多字节 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-900x41-0x5a)的范围内,所以字节保留为-是。

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

【讨论】:

    【解决方案2】:

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

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

    bash-3.2$ echo "TOMÀS VICENÇ ROMÀ" |LC_CTYPE=C gawk '{ print tolower($0)}'
    
    tomÀs vicenÇ romÀ
    
    
    bash-3.2$ echo "TOMÀS VICENÇ ROMÀ" |LC_CTYPE=C gawk '{ print $0}'|tr '[:upper:]' '[:lower:]'
    
    tomàs vicenç romà
    

    【讨论】:

      猜你喜欢
      • 2014-01-15
      • 1970-01-01
      • 1970-01-01
      • 2014-12-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多