-
Notifications
You must be signed in to change notification settings - Fork 72
Expand file tree
/
Copy pathoos_util_base.pkb
More file actions
195 lines (190 loc) · 5.81 KB
/
oos_util_base.pkb
File metadata and controls
195 lines (190 loc) · 5.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
create or replace package body oos_util_base
as
/**
* Converts decimal (base10) numbers to other bases
*
* Notes:
* - Based on code from Tom Kyte's blog: http://www.oracle.com/technetwork/issue-archive/2006/06-jul/o46asktom-085866.html
* - and @connormcd comment: https://github.com/OraOpenSource/oos-utils/issues/173#issuecomment-341342912
*
* @issues #67, #128
*
* @example
*
* select oos_util_base.to_base(123, 12)
* from dual;
*
* OOS_UTIL_STRING.TO_BASE(123, 12)---
* A3
*
* @author Zach Hudock
* @created 26-Jun-2017
* @param p_int pls_integer
* @param p_base pls_integer
* @return string p_base-converted value of p_int
*/
function to_base(
p_int in pls_integer,
p_base in pls_integer,
p_alphabet in varchar2 default gc_symbols)
return varchar2
as
l_str varchar2(256 char) default null;
l_quotient pls_integer := p_int;
l_truncated pls_integer;
l_remainder pls_integer;
begin
oos_util.assert(p_int >=0 and round(p_int, 0) = p_int, 'p_int must be a positive whole number');
oos_util.assert(p_base between 2 and 62, 'p_base must be between 2 and 62');
oos_util.assert(p_base <= length(p_alphabet), 'length of p_alphabet can not be smaller than p_base');
for i in 1..length(p_alphabet) loop
oos_util.assert(length(regexp_replace(p_alphabet, '[^' || substr(p_alphabet, i, 1) || ']')) = 1, '[' || substr(p_alphabet, i, 1) || '] appears in p_alphabet multiple times');
end loop;
if (p_base = gc_decimal) then
l_str := sys.standard.to_char(p_int);
elsif (p_base = gc_hex) then
l_str := upper(trim(sys.standard.to_char(p_int, rpad('x',63,'x'))));
else
while l_quotient > 0 loop
l_truncated := trunc(l_quotient / p_base);
l_remainder := l_quotient - l_truncated * p_base;
l_quotient := l_truncated;
l_str := substr(p_alphabet, l_remainder+1, 1) || l_str;
end loop;
end if;
return l_str;
end to_base;
/**
* Converts decimal (base10) numbers to binary
*
* @TODO: determine if spacing should be constrained to multiples of 2, 4 or no constraints
*
* @issues #67, #128
*
* @example
*
* select oos_util_base.to_binary(123, 4)
* from dual;
*
* OOS_UTIL_STRING.to_binary(123, 4)---
* 0111 1011
*
* @author Zach Hudock
* @created 26-Jun-2017
* @param p_int pls_integer
* @param p_space_every pls_integer number of chars to use for spacing binary string
* @return string binary value of p_int
*/
function to_binary(
p_int in pls_integer,
p_space_every in pls_integer default 0)
return varchar2
as
l_str varchar2(320 char) default null;
begin
oos_util.assert(mod(p_space_every, 4) = 0, 'p_space_every must be divisible by 4');
l_str := oos_util_base.to_base(p_int, gc_binary);
if p_space_every > 0 then
l_str := lpad(l_str, ceil(length(l_str) / p_space_every) * p_space_every , '0'); --left pad with 0 to nearest multiple of p_space_every
l_str := regexp_replace(l_str, '([01]{' || p_space_every || '})', ' \1'); --replace each grouping of p_space_every chars with space + self
end if;
return trim(l_str);
end to_binary;
/**
* Converts decimal (base10) numbers to octal (base8)
*
* @issues #67, #128
*
* @example
*
* select oos_util_base.to_octal(123)
* from dual;
*
* OOS_UTIL_STRING.to_octal(123)---
* 173
*
* @author Zach Hudock
* @created 26-Jun-2017
* @param p_int pls_integer
* @return string octal value of p_int
*/
function to_octal(
p_int in pls_integer)
return varchar2
as
begin
return oos_util_base.to_base(p_int, gc_octal);
end to_octal;
/**
* Converts decimal (base10) numbers to hexidecimal (base16)
*
* @issues #67, #128
*
* @example
*
* select oos_util_base.to_hex(123)
* from dual;
*
* OOS_UTIL_STRING.to_hex(123)---
* 7B
*
* @author Zach Hudock
* @created 26-Jun-2017
* @param p_int pls_integer
* @return string hexidecimal value of p_int
*/
function to_hex(
p_int in pls_integer)
return varchar2
as
begin
return oos_util_base.to_base(p_int, gc_hex);
end to_hex;
/**
* Converts other bases to decimal (base10) numbers
*
* Notes:
* - Based on code from Tom Kyte's blog: http://www.oracle.com/technetwork/issue-archive/2006/06-jul/o46asktom-085866.html
*
* @issues #67, #128
*
* @example
*
* select oos_util_base.to_number('AA', 11)
* from dual;
*
* OOS_UTIL_STRING.to_number('AA', 11)---
* 120
*
* @author Zach Hudock
* @created 26-Jun-2017
* @param p_str varchar2
* @param p_base pls_integer
* @return string base10 value of p_str
*/
function to_decimal(
p_str in varchar2,
p_base in pls_integer,
p_alphabet in varchar2 default gc_symbols)
return pls_integer
as
c_str constant varchar2(256 char) := case when p_base <= 36 then upper(p_str) else p_str end;
l_num pls_integer default 0;
begin
oos_util.assert(regexp_replace(c_str, '[' || substr(p_alphabet, 1, p_base) || ']') is null, c_str || ' contains invalid characters for Base' || p_base);
oos_util.assert(p_base between 2 and 62, 'p_base must be between 2 and 62');
oos_util.assert(p_base <= length(p_alphabet), 'length of p_alphabet can not be smaller than p_base');
for i in 1..length(p_alphabet) loop
oos_util.assert(length(regexp_replace(p_alphabet, '[^' || substr(p_alphabet, i, 1) || ']')) = 1, '[' || substr(p_alphabet, i, 1) || '] appears in p_alphabet multiple times');
end loop;
if (p_base = gc_hex) then
l_num := sys.standard.to_number(c_str, rpad('x',63,'x'));
else
for i in 1 .. length(c_str) loop
l_num := l_num * p_base + instr(p_alphabet,substr(c_str,i,1))-1;
end loop;
end if;
return l_num;
end to_decimal;
end oos_util_base;
/