[20190930]oracle number类型存储转化脚本.txt
--//没事写了一个oracle number类型存储转化脚本。本来想用C来编写,感觉不好写。
--//还是采用自己擅长的bash编程。
--//关于oracle number如何编码可以看yangtingkun的blog,链接如下:
--//http://blog.itpub.net/4227/viewspace-68510/=>Oracle基本数据类型存储格式浅析(二)——数字类型
1.数据的输入问题:
--//可能输入的数据并不"归整",比如 0 ,可能输入 0.00,或者-0.可能输入有逗号空格等等。
--//另外就是输入的数字可能是2.1000000 或者 5.00000000之类的情况,必须先预处理。
--//另外说明一下:我脚本输入数据不支持科学记数法。比如1e4之类的写法。
--//通过简单的加0处理,另外如果字串太长,执行bc后会折行,必须删除"\n\\\r"字符(注:windows下bc的输出带\r字符。)
--//主要代码如下:
v_num=$(echo $v_num + 0 | bc -l | tr -d '\n\\\r' | sed -e "s/\.\([0-9]*[1-9]\)0\+$/.\1/" -e "s/\.0\+$//")
2.负数处理的问题:
--//负数结尾要补上0x66作为结束。实际上如果位数很多小数点后有40位,不需要加上0x66。
--//补上0x66实际上为了排序的需要,负数越大实际上越小。
--//我的处理先转化正数,设置v_sign=1表示负数。
3.如何获得幂指数。
--//oracle number采用百进制表示,我开始采用bc l函数(实际上ln函数)获得幂指数,感觉这个存在精度的问题,而且使用bc math库函数。
--//最终放弃这个方案。
--//后来仔细思考可以利用".",只要知道"."在数字串的位置就可以知道对于100的幂指数,具体看代码:
--//获得字串"."位置可以使用expr命令,例子如下:
v_pos=$(expr index $v_num ".")
4.剩余部分的编码(小数点部分):
--//我仅仅执行如下,特别定义scale=180,基本不会精度问题,删除尾部0(小数点之后),注意看sed部分,最后删除开头的小数点。
v_tmp=$(echo "scale=180 ; $v_num / 100^($v_exp) " | bc | tr -d '\n\\\r'| sed -e "s/\.\([0-9]*[1-9]\)0\+$/.\1/" -e "s/\.0\+$//" -e "s/^\.//")
--//因为oracle number采用百进制,要保证v_tmp的长度是偶数,如果不是在结尾不0。
--//剩下的就简单了。
5.测试:
$ cat test.txt
0
1
2
25
123
4100
-4100
41000000
-41000000
132004078
2.01
.3
.00000125
115.200003
-.00000125
-.3
-1
-5
-20032
-234.432
999999999999999999999999999999999999999900000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-999999999999999999999999999999999999999900000000000000000000000000000000000000000000000000000000000000000000000000000000000000
.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
-.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
123456789012345678901234567890123456789012
-123456789012345678901234567890123456789012
0.123456789012345678901234567890123456789012
-0.123456789012345678901234567890123456789012
$ cat test.txt | xargs -n 1 -I {} bash -c "echo {} ;./num2raw.sh {}" | paste - -
0 80
1 c1,02
2 c1,03
25 c1,1a
123 c2,02,18
4100 c2,2a
-4100 3d,3c,66
41000000 c4,2a
-41000000 3b,3c,66
132004078 c5,02,21,01,29,4f
2.01 c1,03,02
.3 c0,1f
.00000125 be,02,1a
115.200003 c2,02,10,15,01,04
-.00000125 41,64,4c,66
-.3 3f,47,66
-1 3e,64,66
-5 3e,60,66
-20032 3c,63,65,45,66
-234.432 3d,63,43,3a,51,66
999999999999999999999999999999999999999900000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ff,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64
-999999999999999999999999999999999999999900000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00,02,02,02,02,02,02,02,02,02,02,02,02,02,02,02,02,02,02,02,02
.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 80,02
-.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 7f,64,66
123456789012345678901234567890123456789012 d5,0d,23,39,4f,5b,0d,23,39,4f,5b,0d,23,39,4f,5b,0d,23,39,4f,5b
-123456789012345678901234567890123456789012 2a,59,43,2d,17,0b,59,43,2d,17,0b,59,43,2d,17,0b,59,43,2d,17,0b
0.123456789012345678901234567890123456789012 c0,0d,23,39,4f,5b,0d,23,39,4f,5b,0d,23,39,4f,5b,0d,23,39,4f,5b
-0.123456789012345678901234567890123456789012 3f,59,43,2d,17,0b,59,43,2d,17,0b,59,43,2d,17,0b,59,43,2d,17,0b
SCOTT@test01p> select a,dump(a,16) c80 from ty;
A C80
---------- --------------------------------------------------------------------------------
0 Typ=2 Len=1: 80
1 Typ=2 Len=2: c1,2
2 Typ=2 Len=2: c1,3
25 Typ=2 Len=2: c1,1a
123 Typ=2 Len=3: c2,2,18
4100 Typ=2 Len=2: c2,2a
-4100 Typ=2 Len=3: 3d,3c,66
41000000 Typ=2 Len=2: c4,2a
-41000000 Typ=2 Len=3: 3b,3c,66
132004078 Typ=2 Len=6: c5,2,21,1,29,4f
2.01 Typ=2 Len=3: c1,3,2
.3 Typ=2 Len=2: c0,1f
.00000125 Typ=2 Len=3: be,2,1a
115.200003 Typ=2 Len=6: c2,2,10,15,1,4
-.00000125 Typ=2 Len=4: 41,64,4c,66
-.3 Typ=2 Len=3: 3f,47,66
-1 Typ=2 Len=3: 3e,64,66
-5 Typ=2 Len=3: 3e,60,66
-20032 Typ=2 Len=5: 3c,63,65,45,66
-234.432 Typ=2 Len=6: 3d,63,43,3a,51,66
~ Typ=2 Len=21: ff,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64
-~ Typ=2 Len=21: 0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2
1.000E-130 Typ=2 Len=2: 80,2
-1.00E-130 Typ=2 Len=3: 7f,64,66
1.2346E+41 Typ=2 Len=21: d5,d,23,39,4f,5b,d,23,39,4f,5b,d,23,39,4f,5b,d,23,39,4f,5b
-1.235E+41 Typ=2 Len=21: 2a,59,43,2d,17,b,59,43,2d,17,b,59,43,2d,17,b,59,43,2d,17,b
.123456789 Typ=2 Len=21: c0,d,23,39,4f,5b,d,23,39,4f,5b,d,23,39,4f,5b,d,23,39,4f,5b
-.12345679 Typ=2 Len=21: 3f,59,43,2d,17,b,59,43,2d,17,b,59,43,2d,17,b,59,43,2d,17,b
28 rows selected.
--//我家里的电脑有点慢,大概每个需要2秒。
6.附上转化脚本如下:
$ cat num2raw.sh
#! /bin/bash
#! number convert oracle raw, input parameter do not like 1.1e3.
odebug=${ODEBUG:-0}
# process input parameter ,delete "," and all spaces. save to variable v_num. and length to variable v_len.
v_num="$*"
v_num=${v_num//[, ]/}
# strip trailing 0s in decimals or 0000.000 output 0
v_num=$(echo $v_num + 0 | bc | tr -d '\n\\\r' | sed -e "s/\.\([0-9]*[1-9]\)0\+$/.\1/" -e "s/\.0\+$//")
if [[ "$v_num" =~ ^-.*$ ]]; then
v_sign=1
v_num=${v_num:1:180}
else
v_sign=0
fi
if [ $odebug -eq 1 ] ; then
echo v_num="$v_num"
fi
v_res=""
if [ "$v_num" == "0" ]; then
v_res="80"
echo "$v_res"
exit 0
fi
# Guarantee . occur
# v_tmp1=$(echo "scale=180; $v_num/1" | bc |tr -d '\n\\\r' | sed -e "s/\.\([0-9]*[1-9]\)0\+$/.\1/")
# v_pos=$(expr index $v_tmp1 ".")
v_pos=$(expr index $v_num ".")
if [ $v_pos -gt 1 ]; then
v_exp=$(( v_pos/2 ))
elif [ $v_pos -eq 0 ]; then
v_exp=$(( (${#v_num}+1) /2 ))
elif [ $v_pos -eq 1 ]; then
v_tmp1=${v_num:1:180}
v_tmp2=$(echo $v_tmp1 | sed 's/^0\+//g')
v_exp=$(( (${#v_tmp2} - ${#v_tmp1})/2 ))
else
echo "number $v_num don't find dot!!"
exit 1
fi
v_exp1=$(printf "%02x" $(( $v_exp+192 )))
if [ $v_sign -eq 1 ]; then
v_exp1=$(printf "%02x" $(( 0xff - 0x${v_exp1} )))
fi
v_res=${v_exp1}${v_res}
v_tmp=$(echo "scale=180 ; $v_num / 100^($v_exp) " | bc | tr -d '\n\\\r'| sed -e "s/\.\([0-9]*[1-9]\)0\+$/.\1/" -e "s/\.0\+$//" -e "s/^\.//")
# oracle number type max length is 22 bytes (not 22 is 21 bytes??), 1 bytes exponent.
v_tmp=${v_tmp:0:40}
v_len=${#v_tmp}
v_tmp1=$(( $v_len % 2 ))
if [ $v_tmp1 -ne 0 ]; then
v_tmp=${v_tmp}"0"
v_len=$(( $v_len+1 ))
fi
if [ $odebug -eq 1 ] ; then
echo v_num="$v_num" v_len="$v_len" v_exp="$v_exp" v_exp1="$v_exp1" v_tmp="$v_tmp"
fi
if [ $v_sign -eq 0 ]; then
for ((i=0;i<$v_len;i+=2))
do
v_tmp1=$(printf "%02x" $(( ${v_tmp:i:2} + 1 )))
v_res=${v_res}","${v_tmp1}
done
else
for ((i=0;i<$v_len;i+=2))
do
v_tmp1=$(printf "%02x" $(( 101 - ${v_tmp:i:2} )))
v_res=${v_res}","${v_tmp1}
done
fi
# for ((i=0;i<$v_len;i+=2))
# do
# if [ $v_sign -eq 0 ]; then
# v_tmp1=$(printf "%02x" $(( ${v_tmp:i:2} + 1 )))
# else
# v_tmp1=$(printf "%02x" $(( 101 - ${v_tmp:i:2} )))
# fi
# v_res=${v_res}","${v_tmp1}
# done
if [ $v_sign -eq 1 -a $v_len -lt 40 ]; then
v_res=${v_res}",""66"
fi
echo "$v_res"
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/267265/viewspace-2658887/ ,如需转载,请注明出处,否则将追究法律责任。