c - glibc 的 isalpha 函数和 en_US.UTF-8 语言环境
问题描述
isalpha
简短版本:当语言环境设置为非C
(换句话说,类似)时,C 函数如何工作en_US.UTF-8
?
长版:在阅读一堆关于该isalpha
函数的文档时,我并不是 100% 清楚它依赖于语言环境的行为是如何工作的。具体来说,我发现文档说诸如
在某些语言环境中,可能存在 isalpha 为真的附加字符——既不是大写也不是小写的字母。但是在标准的“C”语言环境中,没有这样的附加字符。
此外——如果我用一个小型 C 程序对此进行测试,我可以确认当设置不同的语言环境时,isalpha
它将返回true
/1
用于传统 ASCII 文本范围之外的值——对于某些 unix。这个程序似乎在我基于 BSD/Darwin 的 mac 上做了一些合理的事情——但是当我在 ubuntu 机器上尝试它时它出现了段错误。
#include <stdio.h>
#include <ctype.h>
#include <locale.h>
#include <limits.h>
int main() {
setlocale(LC_ALL, "en_US.UTF-8");
for(int i=0;i<INT_MAX;i++) {
// printf() displays the string inside quotation
if(isalpha(i)) {
printf("is alpha numeric: %i\n", i);
}
}
return 0;
}
我不清楚的是isalpha
,当语言环境设置为时,如何知道哪些整数应该返回 trueen_US.UTF-8
以及这些整数代表什么。这只是某个范围内某个范围内的 utf 代码点的硬编码列表吗?还是不那么直接的东西?
我试着自己追这个,但我的鸽子-c 不能胜任这项任务。
我达到了ctype.c
和ctype.h
。如果我深入研究 glibc 的源代码,我会发现该isalpha
函数实际上是一个扩展为类似这样的宏
int isalpha (int c) {
return __isctype (c, _ISalpha);
}
__isctype
也是一个宏,所以我们扩展它我们有类似的东西
int isalpha (int c) {
return ((*__ctype_b_loc ())[(int) (c)] & (unsigned short int) _ISalpha) (c, _ISalpha);
}
并且_ISalpha
枚举扩展到一个小端位掩码,所以现在我们正在研究这样的东西......
int isalpha (int c) {
return ((*__ctype_b_loc ())[(int) (c)] & (unsigned short int) ((2) < 8 ? ((1 << (2)) << 8) : ((1 << (2)) >> 8))) (c, ((2) < 8 ? ((1 << (2)) << 8) : ((1 << (2)) >> 8)));
}
这就是我挖掘出来的地方。
isalpha
除了了解如何工作之外,我没有特别的目标。
解决方案
当语言环境设置为非 C 语言(换句话说,像 en_US.UTF-8 之类的语言)时,C 函数 isalpha 是如何工作的?
Unicode 的前 128 个字符表示与 ASCII 相同,因此没有任何变化(当 C 语言环境使用 ASCII 时)。
真正改变的是,glibc 不再使用硬编码列表,而是打开并加载语言环境文件。我相信/usr/lib/locale/locale-archive
应该包含从/usr/share/i18n/locales/*
文件中编译的语言环境。在我/usr/share/i18n/locales/en_US
看到的文件LC_CTYPE copy "en_GB"
中,我可以转到en_GB
which has copy "i18n"
,然后转到i18n
which has copy "i18n_ctype"
,最后转到具有以下内容的i18n_ctype
文件:
% The "alpha" class of the "i18n" FDCC-set is reflecting
% the recommendations in TR 10176 annex A
alpha /
<U0041>..<U005A>;<U0061>..<U007A>;<U00AA>;<U00B5>;<U00BA>;/
<U00C0>..<U00D6>;<U00D8>..<U00F6>;<U00F8>..<U02C1>;<U02C6>..<U02D1>;/
.... many more lines ....
我可以确认 isalpha 将为传统 ASCII 文本范围之外的值返回 true/1
在所有情况下,参数都是一个 int,其值应表示为无符号字符或应等于宏 EOF 的值。如果参数有任何其他值,则行为未定义。
循环 :for(int i=0;i<INT_MAX;i++) { if(isalpha(i)) {
只是i
更大的未定义行为 then UCHAR_MAX
。有些程序员甚至会这样做isalpha((unsigned char)i)
。is<ctype>(arg)
(我记得在某些情况下,当函数参数不是无符号字符时会收到警告)。
这只是某个范围内某个范围内的 utf 代码点的硬编码列表吗?还是不那么直接的东西?
是的,正如上面在/usr/share/i18n/locales/*
文件中提到的。
C 语言环境的硬编码列表存储在locale/C-ctype.c中,旨在匹配POSIX。
推荐阅读
- oauth-2.0 - 从 WebApp 网站下载 Azure Blob,并使用基于角色的 IAM 访问权限登录 AAD 身份
- mysql - 从产品和供应商那里获得最低价格
- java - 如何将 Appengine Blobstore 与 SpringBoot 和 Thymeleaf 一起使用?
- javascript - 放大和缩小场景中的特定点 THREE.js 和 TWEEN.js
- django - 为什么 Django 会出现此错误:第 3 行的块标记无效:'else'
- elasticsearch - Logstash 不读取日志文件但读取文本文件
- python-3.x - 无法在 API 端点显示 csv 文件输出
- php - Eloquent Count 嵌套关系
- c# - 反序列化自定义组件后如何执行代码?
- android - 如何使用默认的安卓主题?