如何使uc()在Perl中像toupper()在AWK中一样在区域设置敏感的POSIX环境中工作?

如何使uc()在Perl中像toupper()在AWK中一样在区域设置敏感的POSIX环境中工作?,perl,awk,posix,locale,standards-compliance,Perl,Awk,Posix,Locale,Standards Compliance,当我在AWK中使用toupper()之类的函数时,它们会自动识别区域设置并处理用户当前区域设置中的文本 我想在Perl脚本中也这样做,但到目前为止失败了 为此,我编写了以下用于测试Perl和AWK的ASCII shell脚本: $ unexpand -t 2 << 'END_SCRIPT' | tee case3 && chmod +x case3 #! /bin/sh { iconv -cf UTF-7 \ | case $1 in awk) a

当我在AWK中使用toupper()之类的函数时,它们会自动识别区域设置并处理用户当前区域设置中的文本

我想在Perl脚本中也这样做,但到目前为止失败了

为此,我编写了以下用于测试Perl和AWK的ASCII shell脚本:

$ unexpand -t 2 << 'END_SCRIPT' | tee case3 && chmod +x case3
#! /bin/sh
{
  iconv -cf UTF-7 \
  | case $1 in
  awk)
    awk '{
      print "original", $0
      print "to lower", tolower($0)
      print "to upper", toupper($0)
    }'
    ;;
  perl)
    perl -e '
      use locale;
      while (defined($_= <>)) {
        print "original ", $_;
        print "to lower ", lc;
        print "to upper ", uc;
      }
    '
  esac \
  | iconv -ct UTF-7 | iconv -cf UTF-7
} << 'EOF'
+AMQ-gypten
S+APw-d
+APY-stlich
EOF
END_SCRIPT
这看起来很好,应该是这样的

现在Perl也是这样:

$ ./case3 perl
original Ägypten
to lower gypten
to upper ÄGYPTEN
original Süd
to lower sd
to upper SüD
original östlich
to lower stlich
to upper öSTLICH
显然,这会产生不同的输出,而且效果并不理想

我希望知道我在脚本的“perl”案例中犯了什么错误

注意:我不希望我的脚本需要UTF-8语言环境,它应该与任何可以代表test.txt文件中使用的德语Umlauts的语言环境一起工作

如果您感到好奇,以上结果是使用以下区域设置生成的:

$ locale
LANG=de_AT.UTF-8
LANGUAGE=de_AT.UTF-8:de.UTF-8:en_US.UTF-8:de_AT:de:en_US:en
LC_CTYPE="de_AT.UTF-8"
LC_NUMERIC="de_AT.UTF-8"
LC_TIME="de_AT.UTF-8"
LC_COLLATE="de_AT.UTF-8"
LC_MONETARY="de_AT.UTF-8"
LC_MESSAGES="de_AT.UTF-8"
LC_PAPER="de_AT.UTF-8"
LC_NAME="de_AT.UTF-8"
LC_ADDRESS="de_AT.UTF-8"
LC_TELEPHONE="de_AT.UTF-8"
LC_MEASUREMENT="de_AT.UTF-8"
LC_IDENTIFICATION="de_AT.UTF-8"
LC_ALL=

这与您的要求不同,因为它基于Unicode规则而不是区域设置的规则来确定大小写,但它适用于所有区域设置(UTF-8或其他):

使用open':std',':locale';
而(){
打印“原件”,元;
打印“降低”,lc;
打印“至上”,uc;
}

这并不是您所要求的,因为它基于Unicode规则而不是区域设置的规则来确定大小写,但它适用于所有区域设置(UTF-8或其他):

使用open':std',':locale';
而(){
打印“原件”,元;
打印“降低”,lc;
打印“至上”,uc;
}

您的Perl版本是什么?不幸的是,语言环境的设计(通常是实现)存在很多缺陷。Unicode的发明(参见perlunitut的介绍)部分是为了解决这些设计缺陷,现在,有一系列“UTF-8语言环境”“,基于Unicode。这些语言环境的字符集是Unicode,用UTF-8编码。从v5.20开始,Perl完全支持UTF-8语言环境,除了排序和字符串比较,如
lt
ge
。“从v5.26开始,Perl也可以合理地处理这些问题,这取决于平台的实现。但是,对于早期版本或更好的控制,请使用Unicode::Collate。Perl还继续支持旧的非UTF-8语言环境。目前没有适用于EBCDIC平台的UTF-8语言环境。“@ikegami我有perl 5,版本24,subversion 1(v5.24.1)为i686-linux-gnu-thread-multi-64int构建-这是当前的Debian-9版本。@ikegami你能告诉我如何将Unicode::Collate集成到我的上述脚本中吗?正如我快速浏览时所注意到的,Unicode::Collate不关心当前的区域设置。我也不希望我的脚本需要Unicode区域设置。我不是t建议您使用U::C;我只是指出了不同版本的Perl的问题。如果您尝试排序(而不是更改大小写),则更适合您。您的Perl版本是什么?“不幸的是,语言环境的设计(通常是实现)存在不少缺陷。Unicode的发明(参见perlunitut的介绍)部分是为了解决这些设计缺陷,现在,有一系列基于Unicode的“UTF-8语言环境”。这些语言环境的字符集是Unicode,用UTF-8编码。从v5.20开始,Perl完全支持UTF-8语言环境,除了排序和字符串比较,如
lt
ge
。“从v5.26开始,Perl也可以合理地处理这些问题,这取决于平台的实现。但是,对于早期版本或更好的控制,请使用Unicode::Collate。Perl还继续支持旧的非UTF-8语言环境。目前没有适用于EBCDIC平台的UTF-8语言环境。“@ikegami我有perl 5,版本24,subversion 1(v5.24.1)为i686-linux-gnu-thread-multi-64int构建-这是当前的Debian-9版本。@ikegami你能告诉我如何将Unicode::Collate集成到我的上述脚本中吗?正如我快速浏览时所注意到的,Unicode::Collate不关心当前的区域设置。我也不希望我的脚本需要Unicode区域设置。我不是t建议您使用U::C;我只是指出了不同版本的Perl的问题,将更适合您。谢谢,这实际上对于我的问题来说已经足够好了,因为我的测试用例不涉及排序。否则它仍然会是一个问题。我的意思是,如果我的脚本需要使用区域设置的排序序列,这将是一个问题。但是它没有。您可以用于排序。谢谢,这实际上对于我的q来说已经足够好了uestion,因为我的测试用例不涉及排序。否则它仍然会是一个问题。我的意思是,如果我的脚本需要使用区域设置的排序顺序,那将是一个问题。但它不涉及排序。您可以使用排序。
$ locale
LANG=de_AT.UTF-8
LANGUAGE=de_AT.UTF-8:de.UTF-8:en_US.UTF-8:de_AT:de:en_US:en
LC_CTYPE="de_AT.UTF-8"
LC_NUMERIC="de_AT.UTF-8"
LC_TIME="de_AT.UTF-8"
LC_COLLATE="de_AT.UTF-8"
LC_MONETARY="de_AT.UTF-8"
LC_MESSAGES="de_AT.UTF-8"
LC_PAPER="de_AT.UTF-8"
LC_NAME="de_AT.UTF-8"
LC_ADDRESS="de_AT.UTF-8"
LC_TELEPHONE="de_AT.UTF-8"
LC_MEASUREMENT="de_AT.UTF-8"
LC_IDENTIFICATION="de_AT.UTF-8"
LC_ALL=
use open ':std', ':locale';
while (<>) {
    print "original ", $_;
    print "to lower ", lc;
    print "to upper ", uc;
}