如何查找给定字符编码的区域设置名称?

如何查找给定字符编码的区域设置名称?

的手册页setlocale似乎是说语言代码和字符编码名称足以设置适当的区域设置:

区域设置名称通常采用 language[_territory][.codeset][@modifier] 形式,其中 language 是 ISO 639 语言代码,region 是 ISO 3166 国家/地区代码,codeset 是字符集或编码标识符,例如 ISO- 8859-1 或 UTF-8。

然而,快速测试表明,只有区域设置名称的“修饰符”部分是可选的:

void tryLocale(const char * locid)
{
    char * result = std::setlocale(LC_CTYPE, locid);
    std::cout << locid << " = " << (result ? result : "fail") << std::endl;
}

int main()
{
    tryLocale("de");           // de = fail
    tryLocale("de_DE");        // de_DE = fail
    tryLocale("de_DE.CP1252"); // de_DE.CP1252 = de_DE.CP1252
    tryLocale("de.CP1252");    // de.CP1252 = fail
    tryLocale(".CP1252");      // .CP1252 = fail
}

我的问题是我只知道所需的编码名称(例如ISO-8859-1),并且我可能会想出语言代码(例如en)。我不知道如何找到合适的国家/地区名称(例如US),而且我对国家/地区不感兴趣:我只想像tolower我的应用程序中那样的功能使用正确的代码页。

答案1

我想你必须循环浏览它们。在zsh

for l (${(f)"$(locale -a)"}) 
  [[ $(LC_ALL=$l locale charmap) = ISO-8859-1 ]] && print -r -- $l

或者在模块$langinfo中使用其特殊关联数组进行相同的操作zsh/langinfo

zmodload zsh/langinfo
for LC_ALL (${(f)"$(locale -a)"})
  [[ $langinfo[CODESET] = ISO-8859-1 ]] && print -r -- $LC_ALL

将列出使用 ISO-8859-1 作为字符映射的所有可用区域设置。

但请注意,LC_CTYPE指定字符映射/代码集的类别还涵盖字符分类:什么是小写字母,什么是标点符号等,以及音译(如 所使用的tolower()),两者都可能因地区/国家而异。即使使用相同的代码集,下一个也是如此。

例如,查看 GNU 土耳其语语言环境中的小写形式Iı无论使用什么字符映射(UTF-8、ISO-8859-9...),而i在大多数其他也使用 UTF-8 的语言环境中也是如此。

您可以查看区域设置源定义,例如:

(cd /usr/share/i18n/locales && pcregrep -Me '(?ms)^LC_CTYPE.*?^END' -- *)

在 GNU 系统上查看该LC_CTYPE类别跨区域设置的差异。您不会在那里找到字符映射,这些文件和字符映射的组合的区域设置是使用 生成的localedef -i thosefiles -f charmap,尽管只有某些组合有意义,请参阅/usr/share/i18n/SUPPORTED参考资料 的列表。

例如,en_GB您系统上的区域设置可能是使用localedef -i locales/en_GB -f charmaps/ISO-8859-1.gz和生成en_GB.UTF-8localedef -i locales/en_GB -f charmaps/UTF-8.gz

因此,在这里,也许您需要找到一个用作ISO-8859-1字符映射的语言环境,但也需要具有在英国大陆对于英国英语或意大利/德国等德语使用者有意义的音译规则和字符分类,例如满足:

[[ $(locale language)  = 'British English' &&
   $(locale territory) = 'United Kingdom' &&
   $(locale charmap)   = ISO-8859-1 ]]

这应该会稍微缩小选择范围。

请注意,languageterritory是非标准 GNU 扩展,这解释了为什么您在 zsh 的$langinfo. GNU libc 文档 ( info libc langinfo) 仅提到:

文件“langinfo.h”定义了更多符号,但它们都不是官方的。使用它们是不可移植的,并且返回值的格式可能会改变。因此我们建议(原文如此)您不要使用它们。

/usr/include/langinfo.h我的系统上有:

  _NL_IDENTIFICATION_LANGUAGE,
  _NL_IDENTIFICATION_TERRITORY,

另请参阅locale -k LC_IDENTIFICATIONlocale -k LC_CTYPE了解 GNU 系统上给定语言环境类别支持的关键字列表(locale -kc LC_ALL过去可以工作,但现在显然不再有效)。

相关内容