如何在 JavaScript 中实现 ctype.h 功能?

How to implement ctype.h functionality in JavaScript?

glibc ctype.h 翻译成 JavaScript 的一般方法是什么?我想我可以做到,但我没有在 C 源代码中找到实现这些的 tables 和位移位。这里最优化的技术是什么?

isalnum(c)
isalpha(c)
iscntrl(c)
isdigit(c)
islower(c)
isgraph(c)
isprint(c)
ispunct(c)
isspace(c)
isupper(c)
isxdigit(c)
isblank(c)

看来他们正在使用各种技术来生成这些函数,这些函数可能取决于体系结构。但是,将其手动翻译成 JavaScript 需要做什么的要点是什么?看来他们正在使用某种 tables,但我似乎也无法在源代码中找到它们。

查看 openbsd ctype.h source 让我更接近一点,但仍然缺少 table,并且不确定这是否是用于 JavaScript 的最优化方法。例如:

__only_inline int isdigit(int _c)
{
  return (_c == -1 ? 0 : ((_ctype_ + 1)[(unsigned char)_c] & _N));
}

我不知道他们从哪里得到 & _N,以及 (_ctype_ + 1)[index] 的含义或来源。

他们将 _ctype_ 定义为:

extern const char   *_ctype_;

但不是 C 方面的专家,我不确定如何解释 extern 部分,或者我在哪里可以找到这个 table 实现。可能是 ctype_.c,但还不确定该怎么做。

关于 OpenBSD 实现的发言:

您发现的是一个充满位掩码的查找 table,其大小与 unsigned char (0-255) 的范围相匹配,其中包含 ASCII table (0-127).

上限 (128-255) 用零填充。

请注意前面有一个字节,它为所有内容提供了 +1 的偏移量。

各个掩码定义在 ctype.h 的顶部:

#define _U  0x01
#define _L  0x02
#define _N  0x04
#define _S  0x08
#define _P  0x10
#define _C  0x20
#define _X  0x40
#define _B  0x80

请注意,它们的二进制表示都是一个单独的、不同的位。

isXXX 函数将其参数接收为 int,在对 EOF (-1) 进行初始测试后,它被限制为 unsigned char .此十进制值用于索引查找 table,检索表示每个 ASCII 字符质量的值。

例如,ASCII table 的前 32 个字符是 control 字符,此处用掩码 _C.

表示

LFline-feed 既是 control 又是space个字符。它的十进制值为10 (0xA).

在查找 table 中找到这个索引,我们看到掩码是由按位 ORing _C_S 形成的,如下所示在 _C|_S.

isXXX 函数使用位 AND (&) 和适当的位掩码来测试质量。

例如,isalnum 测试 U 大写、L 小写和 N带掩码的数字 (_U|_L|_N).


可以在 JavaScript 中采用相同的方法。大致:

const _U = 0x01;
const _L = 0x02;
const _N = 0x04;
/* ... */
const _X = 0x40;

const lookup = {
    'A': _U | _X,
    /* ... */
    '0': _N,
    /* ... */
    'e': _L | _X,
    'p': _L,
};

const get = c => lookup[c] ?? 0;
const isupper = c => get(c) & _U;
const isxdigit = c => get(c) & (_N | _X);

for (let letter of "Apple0")
    console.log(isupper(letter), isxdigit(letter));

请注意,此处的所有内容或多或少都与“C”有关locale. Switching locales changes the behaviour of these functions (man 7 locale)。