从gawk中的Char返回uint值

从gawk中的Char返回uint值,awk,ord,Awk,Ord,我试图获取通过RS232接收的ASCII字符的值,将其转换为类似二进制的值 例如: 0xFF-->######## 0x01--> # 0x02--> # ... 我的问题是获取大于127的ASCII字符值 测试代码以获取int值: echo-e“\xFF”| gawk-l ordchr-e'{printf(“%c:%i”、ord($0)、ord($0))} 返回: � : -1 测试代码2: echo-e“\x61”| gawk-l ordchr-e'

我试图获取通过RS232接收的ASCII字符的值,将其转换为类似二进制的值

例如:

0xFF-->########
0x01-->       #
0x02-->      #
...
我的问题是获取大于127的ASCII字符值

测试代码以获取int值:
echo-e“\xFF”| gawk-l ordchr-e'{printf(“%c:%i”、ord($0)、ord($0))}

返回:
� : -1

测试代码2:
echo-e“\x61”| gawk-l ordchr-e'{printf(“%c:%i”、ord($0)、ord($0))}

返回:
a:97

因此,我将值转换为无符号int的解决方案如下:

if(ord($0)<0)
{
    new_char=ord($0)+256;
}
else new_char = ord($0)+0`
0xFF
返回:

� : 0
a : 97
0x61
返回:

� : 0
a : 97
有人能解释一下我的行为吗

我正在使用:
GNU Awk 4.1.3,API:1.1(GNU MPFR 3.1.4-p1,GNU MP 6.1.1)

但我想知道是否有一种方法可以在gawk中直接将int转换为uint

实际上,awk中的任何字符串最终都是一个数字

字符串转换为数字,数字转换为字符串, 如果awk程序的上下文需要它。[…]字符串是 通过解释字符串的任何数字前缀转换为数字 如数字所示:“2.5”转换为2.5,“1e3”转换为1000,以及 “25fix”的数值为25。无法解释的字符串 当有效数字转换为零时

让我们做一个快速测试:

BEGIN { 
   print 0xff
   print 0xff + 0
   print 0xff +0.0
   print "0xff"
}

# 255
# 255
# 255
# 0xff
因此,任何
hex
都会自动解释为
uint
。将
int
转换为
uint
是一个棘手的问题:通常,您应该将
int
的模数转换为十六进制,然后将符号位添加为MSB(即,如果数字为非正)。但在awk中不需要这样做

请记住,转换是通过调用
sprintf()
进行的,您可以通过
CONVFMT
变量进行控制:

CONVFMT

控制数字到字符串转换的字符串 (见第节)。它的工作原理是 实际上,作为sprintf()函数的第一个参数传递 (见第节)。其默认值为 “%.6g”。CONVFMT是由POSIX标准引入的

请记住,区域设置可能会影响转换的执行方式,尤其是使用十进制分隔符时。有关更多信息,请参阅


有人能解释一下我的行为吗

我实际上无法复制它,但我怀疑这行代码:

# only first character is of interest
c = substr(str, 1, 1)
在您的示例中,第一个字符始终为
0
,并且输出应始终相同。我正在测试这个

我再举一个例子:

BEGIN {
    a = 0xFF
    b = 0x61
    printf("a: %d %f %X %s %c\n", a,a,a,a,a)
    printf("b: %d %f %X %s %c\n", b,b,b,b,b)
}

# a: 255 255.000000 FF 255 ÿ
# b: 97 97.000000 61 97 a

在二进制模式下运行gawk
gawk-b
以阻止它预缝合UTF8代码点。通过//空字符串将其拆分,则结果数组中的每个点都将包含1字节宽的内容

另一方面,只需预先制作一个从0到256的数组。呆头呆脑的行为根本就不止于此。在我的例行gawk启动序列中,我从
0x3134F
一直执行相同的自定义ord序列,直到零(大约210k左右)。不管出于什么原因,向后执行的原因是,有些代码点会出现一个gawk无法区分的相同字符。反向操作将确保为其分配最低的代码点。对于这种模式,我在常规utf8模式下运行它

对于您的场景,我将预先制作4个十六进制宽数组,从
0x0000
0xFFFF
,返回到它们的整数,然后对于每个
0xZZ 0xWW
,将
ZZWW
抛出到该查找字典中并返回整数

如果您只是尝试从128到255执行
ord()
,通常不会这样做,因为128是unicode从2个字节开始的位置<代码>0x800开始3个字节,
0x10000开始4个字节。我对那些将ascii扩展到256的代码不太熟悉——它们通常需要使用
iconv
或类似的代码才能首先返回UTF-8

如果您想获取原始UTF8字节并试图计算出有多少缝合的UTF8代码点,只需删除所有内容
0x80-0xBF
。残差的
length()
是代码点的数量

在十进制术语中,从0到255的64个数字的4个范围中:

  • 000-063
    -ASCII

  • 064-127
    -ASCII

  • 128-191
    -UT8多字节连续编码(0x80 0xBF

  • 192-255
    -UTF8多字节字符的最高有效字节

  • 这看起来很可怕。幸运的是,奥克塔尔救了我。
    0x80-0xBF
    范围正好是
    \200-\277
    。您可以使用AWK的任何正则表达式来查找这些(也适用于FS/RS等)。我花了很多时间手动编写utf8算法,然后才进行所有的位移位,后来我意识到我不需要这些来实现我的最终目标


    如果您想在将上述逻辑与
    mawk2
    组合时计算utf8代码点,则可以轻松击败系统内置的
    wc-m
    命令。在我2.5岁的笔记本电脑上,与一个满是unicode的1.83 GB平面文本文件相比,我用了大约19秒的时间来计算出12.9亿个utf8代码点,我自己也遇到了同样的问题。我最后使用了一个检测器,它是以unicode模式还是字节模式运行gawk(检查组成一个UTF8代码点的3个八进制值组合的length(),返回1或3)

    然后,当它看到gawk unicode模式时,从gawk运行一个自定义shell命令,并使用unix printf打印出128-255字节,然后将其分块返回到gawk数组中。如果你需要的话,我可以在某个时候粘贴代码(但它太可怕了,所以我希望我不会因为它缺乏优雅而被指责)

    因为UTF8中不存在像C0、C1或FF等这样的字节,不管您使用什么组合