去了一个与世隔绝的地方呆了近一个月,感觉好久没上了,继续写吧。也有说这些内容太繁琐,意义不大的。emmm,确实是比较基础,写下来也是为了方便后面自己查找用。如果用都不会用,直接了解原理还是有点不太习惯,哈哈。先知道是什么,再了解为什么。
剩余的字符串操作函数
substring ( bytes bytea [ FROM start integer ] [ FOR count integer ] ) → bytea
常规的取子串方法,一共3个参数:
- bytes。操作的目标字符串
- FROM。起始索引位置。这里仍然要注意,索引值是从1开始,PG好像不太喜欢索引从0开始
- FOR。要取的子串长度
注意:FROM和FOR至少有一个,要么指定起始位置,要么指定字串长度
举例:
异常情况下的起始位置和长度超出范围自行试下即可,比较简单
trim ( [ LEADING | TRAILING | BOTH ] bytesremoved bytea FROM bytes bytea ) → bytea
这个trim函数是从指定的字符串中按指定方式去除包含指定的字符串的最长字符串,参数有3个:
- 去除方式。LEADING | TRAILING | BOTH,分别表示从开头、从结尾和包括开头和结尾。该参数为可选参数,如果没写,默认为BOTH
- bytesremoved。
这里要特别注意下:
- 这里表示要去除的字符串一定是bytesremoved的一个子串,可以和bytesremoved相等,也可以是bytesremoved的一部分。
- 不能理解为如果找不到bytesremoved表示的字符串就不截取。
- 有效的子串是可以从bytesremoved提取的最长的子串,提取的时候是不考虑位置的,但一定是提取最长的子串
- bytes。原始字符串
举例:
这2个例子应该足够表达清楚这个函数处理的逻辑了
trim ( [ LEADING | TRAILING | BOTH ] [ FROM ] bytes bytea, bytesremoved bytea ) → bytea
这个变种的trim函数是一个非标用法,了解即可,实际使用过程中用楼上那个方法即可
二进制操作函数
bit_count ( bytes bytea ) → bigint
其实是获取字符串的二进制编码中,位为1的个数,这里需要考虑字符串的编码。官方文档中对这个函数做的解释不是很好理解,它的原文是这样的:
Returns the number of bits set in the bit string (also known as “popcount”).
话不多说,先上示例。
示例:
这里考虑了不同语言文字的编码,加了点汉字,
我尝试通过不同的字符和长度来寻找其中的规律,但是长度越长,规律越来越找不到,加上中文字符后直懵圈了:这到底统计的是个啥?不像是统计有多个个bit位,但是看这名字它就是干这个活的。
看到这,心里产生了一个想法,这个字符串是不是在传入PG的时候做了什么处理?
我找了下源代码,在varlena.c文件中有这么一个函数
注意注释,写的是bit_count,你知道它是想表达个啥吗?人家老外知道,但是对我来说头一次看是不清楚的。看来国外的程序员也有摸的时候。
之前提到该函数在在线文档当中提到了一个popcount,我们看第二行代码当中就有这么一个关键字,我们点进去看看:
好了,写这个函数的程序员很优秀,看注释,翻译过来就是统计buf变量中1的个数,buf是个啥,是一个const char*指针,也就是一个常量字符指针,说白了就是一个字节,这里应该就明白了,它在统计一个字节中位为1的个数。注意#if这个预处理,后面那个在代码中找不到的,是一个环境变量,是在安装PG的时候就已经设置进去了。至此我们已经知道这个bit_count到底是在做什么的了,但是不妨再深入进去看个东西,因为我的机器是64位的,走的上面那个分支,我们就看下pg_popcount64这个函数:
好了,这是最终执行的函数,因为返回的是result,整个函数中对result赋值的只有一个pg_number_of_ones操作,点进去看看:
对,结果就是用这个数组算出来的,啥意思,其实就是一个常量表,告诉你哪个值当中有多少个1,数值就是该数组的索引值,怎么理解呢:
比如说0,0这个值的二进制中没有1个1,查出来应该是0,那0对应在这个数组中的索引是几呢,因为是0,所以就找0索引处的,你看是1不?
类似的可以尝试找下1,2,一直到255,我们随便找几个
255:
36:
一个算出来是8,一个算出来是2,对照上面那张表,都是对得上的。
get_bit ( bytes bytea, n bigint ) → integer
从第一个参数表示的字符串中提取第个位置的位值,这里注意2点:
1. n必须是一个有效的索引,索引值从0开始,超出范围函数会直接报错
2. 索引位置的顺序从逻辑上来看,是取的从字符串对应逻辑字节序列的最低位开始的,也就是最右边,且应当与CPU的大小端无关,笔者的CPU是Intel的架构,是小端,大端机器没有试过,不作保证。但是作为一款成熟的工业级软件,在处理这种顺序上应该是有一套标准的,不会因为机器的字节序列架构不同而对函数的调用结果产生影响
示例如下:
02和01的二进制分别为0000 0010和0000 0001,这是逻辑上的表示,可以看出是从逻辑上的低位开始的
get_byte ( bytes bytea, n integer ) → integer
1. 这里稍微注意下,同样索越界会报错
2. 索引的起始位置不再是从逻辑序列上的低位开始算了,而是从高位开始算,也就是左边算起
3. 得到的结果是对应字节的十进制表示
与上述get_bit类似,只不过这个函数取的是字节而不是位,我们直接测试一下
可以看到,第一个值取的是AF对应的十进制175,另一个则是取的01对应的十进制1
length ( bytea ) → integer
统计字符串转换成二进制序列后,一共有几个字节
这里稍微注意一下的是,因为笔者都是用16进制字符串来转换的,如果传入的16进制字符串个数为奇数,会直接报错,因为字节数不完整
这个比较简单,不再详述
length ( bytes bytea, encoding name ) → integer
该函数根据指定的编码格式对指定的字节序列对应的字符个数进行统计。注意,这里统计的是字符个数
看示例:
这里用UTF-8和GBK2种编码对字符串做了统计对比,具体2种编码的逻辑这里不再赘述。但是要注意一下,默认字符串是会被解释成UTF-8编码格式的,上图上最后一个转换如果直接写成以下格式,会报错,如果要按其它编码格式统计,需要强制转换成对应的编码
注意,这里因为没有做转换,导致了【王】字以UTF-8编码,但该编码在GBK的编码表中找不到,出现了错误。
注意:这里有一个小技巧,如果想知道这个逻辑在PG里面是哪段代码报的错,可以想办法生成一个错误,系统会将错误的堆栈打印出来,可以引导去PG源代码里面找它的处理逻辑
md5 ( bytea ) → text
这个不赘述了,将字节进行MD5加密,注意处理好编码格式即可
好了,今天就写到这吧。这几个函数研究源代码花了点时间,剩下的函数下次再写上去吧