打印POSIX字符类

5

假设有一个类,比如:

[:digit:]

我希望输出结果是:
0123456789

注意,这个方法应该适用于所有POSIX字符类。以下是我尝试过的内容:

$ printf %s '[:digit:]'
[:digit:]

§ 字符类


获取当前语言环境中给定字符类别列表的命令。 - phuclv
6个回答

3

我相信有更好的方法,但这里是一种暴力方法:

for i in {0..127}; do 
    char=$(printf \\$(printf '%03o' "$i"))
    [[ $char =~ [[:alpha:]] ]] && echo "$char"
done

循环遍历所有的十进制字符值,将它们转换为相应的ASCII字符并将其与字符类进行比较测试。
范围可能不正确,但检查似乎有效。
正如其他人在评论中提到的那样,在这种情况下也可以使用"=="运算符而不是"=~",这可能会稍微快一些。

1
在我的系统上,这个程序捕获了52个字符,但错过了101487个。 - that other guy
1
你可以使用模式匹配运算符==代替正则表达式运算符=~ - glenn jackman
@glennjackman 很有趣,我不知道那个。那是一个特殊情况吗? - Tom Fenech
3
字符类在模式和正则表达式中都可以使用,这并不是一个特例。 - chepner
@chepner 谢谢,稍后会编辑。我假设 == 更快? - Tom Fenech

2
与其他建议类似,您可以使用以下方法在当前语言环境中找到所有匹配的Unicode 4.0单码位字形:
for((i=0; i < 0x110000; i++)) {
  printf "\U$(printf "%x" $i)\n"; 
}  | grep -a '^[[:alpha:]]$'

这种方法存在一些问题,以下是其中的一些(并非全部):
- 合并字符,例如$'E\U0301',它由两个代码点组成一个字形(此特定序列规范化为单个代码点É)。对于像马拉雅拉姆语这样完全依赖组合的语言,这尤其令人尴尬。 - 它在cntrl类中存在一些问题,具体来说是换行符。 - Ruby字符,我似乎无法在Stack Overflow上呈现。幸运的是,这些通常已被弃用,转而采用适当的标记。 - 它很慢。
更好的方法是尝试解释您平台的区域设置定义文件,但这高度依赖于平台。

1
$ seq 126 | awk '{printf "%c", $0}' | grep -o '[[:digit:]]'
0
1
2
3
4
5
6
7
8
9

1

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脚本,并根据环境、计算机和操作系统获得完全不同的结果。
尽管阿拉伯数字和波斯数字看起来相同,但它们涉及两个不同的Unicode字符点,因此是不同的数字。

2
关于在考虑Unicode时[:digit:]是否包含各种语言中的数字,这是一个很好的观点。字符编码只在考虑解决方案的特定实现时才相关。总的来说,这更像是一个请求澄清原始问题而不是一个答案的评论。 - chepner
1
我不明白不能翻转字符的观点,因为在不同的系统上是不同的。你是否认为 OP 想要动态确定类中的字符的原因是因为他想硬编码列表并分发它? - that other guy

0

另一种“同样但不同”的方法,只是因为OP询问了POSIX字符类,而许多响应依赖于非POSIX组件。

据我所知,这种方法是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 "%s\n" "$(tr -d '\n' < members)"

它还有一个额外的优点,即最终输出可以被修改以用于其他用途。


0

jotseq更方便和灵活。

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-16rrogate 范围为 D800-DFFF, 通过 floor( codepoint / 2^11 ) == 3^3 进行匹配

| A = alpha | U = upper | L = lower | M = alnuM | D = digit | X = xdigit

| G = graph | P = print | T = punct | C = cntrl | S = space | B = blank


          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 \011 \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 | [  ] 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接