打印 POSIX 字符类



给定一个类,例如

[: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:]]可能只包含09的字符。但是,它也可以包括通过٩ ٠字符,或者包括۰۹ 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,尽管我可能滥用printfawk.

我不知道这是否适合所有用例或区域设置,但"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 | [ 𐬿 ] 

相关内容

  • 没有找到相关文章

最新更新