Awk降低以重音开头的字符串-支持外来字符

Awk降低以重音开头的字符串-支持外来字符,awk,character-encoding,diacritics,Awk,Character Encoding,Diacritics,我有一个文件在一行中包含以下字符串:“Ávila” 我想得到这个输出:“ávila” 问题是awk的函数tolower仅在字符串不以重音开头时才起作用,我必须使用awk 例如,如果我做了awk'开始{print tolower(“Ávila”)},那么我得到的是“Ávila”,而不是“ávila”,这就是我所期望的 但是如果我做了awk'BEGIN{print tolower(“Castellón”)},那么我会得到“Castellón”对于给定的awk实现,要正确地处理非ASCII字符(外来字

我有一个文件在一行中包含以下字符串:“Ávila”

我想得到这个输出:“ávila”

问题是awk的函数tolower仅在字符串不以重音开头时才起作用,我必须使用awk

例如,如果我做了awk'开始{print tolower(“Ávila”)},那么我得到的是“Ávila”,而不是“ávila”,这就是我所期望的


但是如果我做了awk'BEGIN{print tolower(“Castellón”)},那么我会得到“Castellón”对于给定的
awk
实现,要正确地处理非ASCII字符(外来字母),它必须尊重活动区域设置的字符编码,这反映在(有效的)
LC\u CTYPE
设置中(运行
locale
查看它)

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

在主要的
awk
实施中

  • GNU Awk(
    gawk
    ),一些Linux发行版上的默认版本
  • BSD
    awk
    ,也用于OS X
  • mawk
    ),基于Debian的Linux发行版(如Ubuntu)的默认版本
只有GNU Awk能够正确处理UTF8编码的字符(如果在区域设置中指定,可能还会处理任何其他编码):

相反,如果您明确希望仅将字符处理限制为ASCII,请在前面添加
LC\u CTYPE=C

$ echo ÁvilA | LC_CTYPE=C gawk '{print tolower($0)}'
Á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上,使用:
      brew安装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-90
    0x41-0x5a
    ),因此字节保持原样

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


我试图对您的回复发表评论,这是正确的,但我需要能够对我添加的内容进行格式化,否则,它将变成胡言乱语

非常有用,我想为大写字母有问题的字母添加以下内容:

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à

使用gnu awk 4.0.1,我从
tolower(“Ávila”)
中得到了“ávila”。顺便说一下:问题与字符串中外来字符的位置无关(在您的第二个命令中,外来字母碰巧已经是小写的),但在某些
awk
实现中,根本无法将非ASCII字母识别为字母。
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à