给定一个类,例如
[:digit:]
我希望输出是
0123456789
请注意,该方法应适用于所有 POSIX 字符类。这是我的试过
$ printf %s '[:digit:]'
[:digit:]
§ 字符类
我相信有更好的方法,但这里有一个蛮力方法:
for i in {0..127}; do
char=$(printf \$(printf '%03o' "$i"))
[[ $char =~ [[:alpha:]] ]] && echo "$char"
done
遍历所有十进制字符值,将它们转换为相应的 ASCII 字符,然后针对字符类对其进行测试。
范围可能是错误的,但检查似乎有效。
正如其他人在评论中提到的,在这种情况下也可以使用 ==
运算符代替 =~
,这可能会稍微快一些。
与其他建议类似,您可以在当前区域设置中找到所有匹配的 Unicode 4.0 单代码点字素:
for((i=0; i < 0x110000; i++)) {
printf "U$(printf "%x" $i)n";
} | grep -a '^[[:alpha:]]$'
以下是此方法的问题的非详尽列表:
组合字符,例如
$'EU0301'
,这是呈现为一个字素的两个码位(此特定序列规范化为单个码位 É(。对于像马拉雅拉姆语这样完全依赖于组合的语言来说,这尤其尴尬。它在
cntrl
类中存在一些问题,特别是换行。Ruby 字符,我似乎无法在 Stack Overflow 上渲染。幸运的是,这些通常被弃用,以支持正确的标记。
它很慢。
更好的方法是尝试解释平台的区域设置定义文件,但这高度依赖于平台。
$ seq 126 | awk '{printf "%c", $0}' | grep -o '[[:digit:]]'
0
1
2
3
4
5
6
7
8
9
POSIX 字符类是内部定义的。对于grep
,您可以通过re_format手册页找到它们。
我们不再生活在基于ASCII的世界里。例如,您可能假设[[:digit:]]
可能只包含0
到9
的字符。但是,它也可以包括通过٩
٠
字符,或者包括۰
到۹
1 的字符,甚至是๐
到 ၉
的字符。这完全取决于您使用的语言以及您如何设置计算机。
此外,我们不能再假设一个字符等同于一个字节。字符现在可以包含多字节序列。使用八进制代码来表示字符并翻译它是行不通的。
这取决于您的计算机和操作系统。如果您在 TRS80 或 PDP11 上编写程序,那么您很有可能仍在使用 ASCII 编码。因此,您可以翻阅所有 127(或 256(种不同的数字编码方式。如果您使用的是 Mac 或 Linux 系统,则使用以 UTF8 编码表示的 Unicode 字符点有一个很好的变化。
在 Windows 上,您可以使用 256 个字符的代码点字符集。默认情况下,这是美国的 CP1252,但在世界各地有所不同。再说一次,Windows也非常擅长Unicode和UTF8。但是,Windows在内部使用UTF16作为其文件系统。
关键是你根本无法翻阅所有字符。您可以在两个不同的系统上运行 shell 脚本,并根据环境、计算机和操作系统获得两个完全不同的结果。
1 虽然它们看起来相同,但阿拉伯语和波斯语数字涉及两个不同的 unicode 字符点,因此是不同的数字。
另一种"相同但不同"的方法,只是因为OP询问了POSIX字符类,而许多响应依赖于非POSIX组件。
AFAIK,这种方法是 100% POSIX,尽管我可能滥用printf
和awk
.
我不知道这是否适合所有用例或区域设置,但"POSIXLY"这似乎适用于 0-127。 它也通过了shellcheck
。
我想您可以根据需要扩展范围。这有点啰嗦,但我认为可读性的成本。
只需将:alpha:
更改为您选择的班级即可。
#!/bin/sh
LC_ALL=C
i=0
true > members
while [ "$i" -le 127 ]
do
echo "$i" | awk '{ printf "%c", $0 }' | awk '/[[:alpha:]]/ { print }'
# echo "$i" | awk '{ printf "%c", $0 }' | grep '[[:alpha:]]'
i=$(( i + 1 ))
done >> members
printf "%sn" "$(tr -d 'n' < members)"
它还有一个额外的优点,即最终输出可以用于其他用途。
jot
比seq
更方便、更灵活。
<小时 />jot -s '' 10 0 # print it numerically jot -s '' -c 10 48 # print it via ASCII ordinals
0123456789
要打印ASCII
大写和小写字母,请执行
<小时 />jot -s '' -c 26 65 # 65 = 9^2 - 4^2 jot -s '' -c 26 97 # 97 = 3^4 + 2^4
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
——————————
更新 : 以下是gawk
如何将POSIX
字符类与UTF-8
匹配的概述(尽管我认为gawk
大约几十个不匹配(:
R
= UTF-16 r
D800-DFFF
的范围,通过floor( codepoint / 2^11 ) == 3^3
匹配
| A
= a
lpha| U
= u
pper| L
= l
| M
= 阿尔努M
| D
= d
igit| X
= x
位
| G
= g
拉夫| P
= p
| T
= 朋克t
| C
= c
ntrl| S
= s
步伐| B
= b
48 RAU_M_XGP____
160 RAU_M__GP____
48 RA_LM_XGP____
160 RA_LM__GP____
80 R___MDXGP____
256 R______GPT___
8 R_______P__SB
8 R_________CSB
32 R_________CS_
224 R_________C__
1,024 R____________ # surrogates D[8-F][8-F][0-F]
6 _AU_M_XGP____
1,179 _AU_M__GP____
6 _A_LM_XGP____
1,346 _A_LM__GP____
31 _A__M__GP____ # in alpha and alnum but neither case
1 __U____GP____ # only in upper but neither alpha nor alnum
1 ___L___GP____ # only in lower but neither alpha nor alnum
10 ____MDXGP____ # just the ASCII digits matched
5,187 _______GPT___
252,248 _______GP____
18 ________P__SB
2 ________P__S_
6 ________P____ ***
1 __________CSB # horizontal-tab 0x09 11 t
5 __________CS_
190 __________C__
851,827 _____________
***
:: 有趣的是,从gawk
的角度来看,这些属于[[:print:]]
,但不属于[[:graph:]]
U+ 10B3A | 68,410 | [ 𐬺 ]
U+ 10B3B | 68,411 | [ 𐬻 ]
U+ 10B3C | 68,412 | [ 𐬼 ]
U+ 10B3D | 68,413 | [ 𐬽 ]
U+ 10B3E | 68,414 | [ 𐬾 ]
U+ 10B3F | 68,415 | [ 𐬿 ]