2022-12-25 16进制文本转10进制数

# 预备知识

在我们看16进制文本转10进制前,先看看Postgres中关于位串的知识

## 预备知识点1:位串常量

总之,前导符号X或x紧跟'十六进制记号文本'也是一种位串常量的表示方式(如: X'FF'),其中每一个十六进制记号字符等价于4个二进制位,详情如下:

位串常量看起来像常规字符串常量在开引号之前(中间无空白)加了一个B(大写或小写形式),例如B'1001'。位串常量中允许的字符只有0和1。作为一种选择,位串常量可以用十六进制记号法指定,使用一个前导X(大写或小写形式),例如X'1FF'。这种记号法等价于一个用四个二进制位取代每个十六进制位的位串常量。两种形式的位串常量可以以常规字符串常量相同的方式跨行继续。美元引用不能被用在位串常量中。

## 预备知识点2:位串常量强制转换中的长度不匹配涉及的截取和补齐规则

如果我们显式地把一个位串值转换成bit(*n*), 那么它的右边将被截断或者在右边补齐零,直到刚好*n*位, 而且不会抛出任何错误。类似地,如果我们显式地把一个位串数值转换成bit varying(*n*),如果它超过了*n*位, 那么它的右边将被截断。

示例:

qianbase=# select x'FF'::bit(32);     

bit       

----------------------------------

11111111000000000000000000000000

(1 row)

qianbase=#

qianbase=#select x'000000FF'::bit(32);     

bit       

----------------------------------

00000000000000000000000011111111

(1 row)

综上两个预备知识点,因此我们在把16进制文本串所表示的位串转换成二进制位串的时候需要根据不足位根据实际缺少的位置(高位还是低位)补齐不足的十六进制文本串0,反之就按照Postgres内部规则自动补齐,结果可能不是你希望的,如上示例。

# 16进制数如何转换为10进制数

Postgres中没有从十六进制数转换为数字类型的函数,因此我们可以使用[bit(n)]作为中间媒介然后转成数值类型。位串中的4位编码1个十六进制数字。从位字符串到bit(32)(最多8个十六进制数字)到[**integer**](标准的4字节整数)实际是一个未记录的强制转换 - 内部表示是二进制兼容。

SELECT ('x' || lpad(hex, 8, '0'))::bit(32)::int  AS int_val FROM ( VALUES ('1'::text)    ,('f')    ,('100')    ,('7fffffff')    ,('80000000')    ,('deadbeef')    ,('ffffffff') ) AS t(hex);

结果:

int_val

------------   

1   

15   

2562147483647

-2147483648

-559038737   

-1

integer有4 byte, 4个字节足以编码*所有*十六进制数字,最多8位数,但Postgres中的integer是有符号类型,因此十六进制数表示**高于'7fffffff'**会溢出到**负数**数字,虽然也是一种表示,因此*含义*是不同的。如果是想用递增的顺序重要,需转到bigint,请参阅下文。

使用[**bigint**](int8,8字节整数)最多16个十六进制数字 - 溢出到上半部分的负数:

SELECT ('x' || lpad(hex, 16, '0'))::bit(64)::bigint AS int8_val FROM ( VALUES ('ff'::text)    , ('7fffffff')    , ('80000000')    , ('deadbeef')    , ('7fffffffffffffff')    , ('8000000000000000')    , ('ffffffffffffffff')    , ('ffffffffffffffff123') ) t(hex);

结果:

int8_val

---------------------       

255   

2147483647   

2147483648   

3735928559

9223372036854775807

-9223372036854775808       

-1       

-1

你可能感兴趣的:(2022-12-25 16进制文本转10进制数)