Código Natural/Notação posicional: mudanças entre as edições
Linha 361: | Linha 361: | ||
Exemplo: para converter <code>0010100101</code> em Base16h, divida em <code>part[0]=00101001</code> de blocos de 4 bits desde o início, e <code>part[1]=01</code>, dos bits restantes. Converta <code>parte[0]</code> em hexadecimal comum (<code>00101001</code> é “29”) e <code>part[1]</code> pela tabela JSON acima (<code>01</code> é “M”), resultando em “29M”. | Exemplo: para converter <code>0010100101</code> em Base16h, divida em <code>part[0]=00101001</code> de blocos de 4 bits desde o início, e <code>part[1]=01</code>, dos bits restantes. Converta <code>parte[0]</code> em hexadecimal comum (<code>00101001</code> é “29”) e <code>part[1]</code> pela tabela JSON acima (<code>01</code> é “M”), resultando em “29M”. | ||
=== Encode e decode Nh === | |||
A seguir o algoritmos completos, expresso através de [[wikipedia:PL/pgSQL|linguagem PLpgSQL]]. Do inglês "''encode''" codifica em base Nh, e "''decode''" decodifica a base Nh. | |||
Função geral de "encode bitstring" para uma base Nh. Converte uma cadeia de bits em texto base2h, base4h, base8h ou base16h. | |||
<syntaxhighlight lang="sql"> | |||
CREATE FUNCTION natcod.vbit_to_baseh( | |||
p_val varbit, -- input | |||
p_base int DEFAULT 4, -- selecting base2h, base4h, base8h, or base16h. | |||
p_nhDigits_upper boolean default false -- represent non-hierarchical digits in upper case | |||
) RETURNS text AS $f$ | |||
DECLARE | |||
vlen int; | |||
pos0 int; | |||
ret text := ''; | |||
blk varbit; | |||
blk_n int; | |||
bits_per_digit int; | |||
tr int[] := '{ {1,2,0,0}, {1,3,4,0}, {1,3,5,6} }'::int[]; -- --4h(bits,pos), 8h(bits,pos) | |||
tr_selected JSONb; | |||
trtypes JSONb := '{"2":[1,1], "4":[1,2], "8":[2,3], "16":[3,4]}'::JSONb; -- TrPos,bits. Can optimize? by sparse array. | |||
trpos int; | |||
baseh "char"[] := array[ -- new 2023 standard for Baseh: | |||
'[0:15]={g,q,x,x,x,x,x,x,x,x,x,x,x,x,x,x}'::"char"[], --1. 1 bit in 4h,8h,16h | |||
'[0:15]={0,1,2,3,x,x,x,x,x,x,x,x,x,x,x,x}'::"char"[], --2. 2 bits in 4h | |||
'[0:15]={h,m,r,v,x,x,x,x,x,x,x,x,x,x,x,x}'::"char"[], --3. 2 bits 8h,16h | |||
'[0:15]={0,1,2,3,4,5,6,7,x,x,x,x,x,x,x,x}'::"char"[], --4. 3 bits in 8h | |||
'[0:15]={j,k,n,p,s,t,z,y,x,x,x,x,x,x,x,x}'::"char"[], --5. 3 bits in 16h | |||
'[0:15]={0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f}'::"char"[] --6. 4 bits in 16h | |||
]; -- jumpping I,O and L,U,W,X letters! | |||
-- the standard alphabet is https://tools.ietf.org/html/rfc4648#section-6 | |||
BEGIN | |||
IF (p_nhDigits_upper) THEN | |||
baseh := array[ | |||
'[0:15]={G,Q,x,x,x,x,x,x,x,x,x,x,x,x,x,x}'::"char"[], --1. 1 bit in 4h,8h,16h | |||
'[0:15]={0,1,2,3,x,x,x,x,x,x,x,x,x,x,x,x}'::"char"[], --2. 2 bits in 4h | |||
'[0:15]={H,M,R,V,x,x,x,x,x,x,x,x,x,x,x,x}'::"char"[], --3. 2 bits 8h,16h | |||
'[0:15]={0,1,2,3,4,5,6,7,x,x,x,x,x,x,x,x}'::"char"[], --4. 3 bits in 8h | |||
'[0:15]={J,K,N,P,S,T,Z,Y,x,x,x,x,x,x,x,x}'::"char"[], --5. 3 bits in 16h | |||
'[0:15]={0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f}'::"char"[] --6. 4 bits in 16h | |||
]; | |||
END IF; | |||
vlen := bit_length(p_val); | |||
tr_selected := trtypes->(p_base::text); -- can be array instead of JSON | |||
IF p_val IS NULL OR tr_selected IS NULL OR vlen=0 THEN | |||
RETURN NULL; -- or p_retnull; | |||
END IF; | |||
IF p_base=2 THEN | |||
RETURN $1::text; --- direct bit string as string | |||
END IF; | |||
bits_per_digit := (tr_selected->>1)::int; | |||
blk_n := vlen/bits_per_digit; | |||
pos0 := (tr_selected->>0)::int; | |||
trpos := tr[pos0][bits_per_digit]; | |||
FOR counter IN 1..blk_n LOOP | |||
blk := substring(p_val FROM 1 FOR bits_per_digit); | |||
ret := ret || baseh[trpos][ varbit_to_int(blk,bits_per_digit) ]; | |||
p_val := substring(p_val FROM bits_per_digit+1); -- same as p_val<<(bits_per_digit*blk_n) | |||
END LOOP; | |||
vlen := bit_length(p_val); | |||
IF p_val!=b'' THEN -- vlen % bits_per_digit>0 | |||
trpos := tr[pos0][vlen]; | |||
ret := ret || baseh[trpos][ varbit_to_int(p_val,vlen) ]; | |||
END IF; | |||
RETURN ret; | |||
END | |||
$f$ LANGUAGE plpgsql IMMUTABLE; | |||
</syntaxhighlight> | |||
Função geral de "decode bitstring" para uma base Nh. Converte o texto base Nh para sua representação interna ''bitstring''. | |||
<syntaxhighlight lang="sql"> | |||
CREATE FUNCTION natcod.baseh_to_vbit( | |||
p_val text, -- input (enforced lower case) | |||
p_base int DEFAULT 4 -- selecting base2h, base4h, base8h, or base16h. | |||
) RETURNS varbit AS $f$ | |||
DECLARE | |||
tr_hdig jsonb := '{ | |||
"g":[1,0],"q":[1,1], | |||
"h":[2,0],"m":[2,1],"r":[2,2],"v":[2,3], | |||
"j":[3,0],"k":[3,1],"n":[3,2],"p":[3,3], | |||
"s":[3,4],"t":[3,5],"z":[3,6],"y":[3,7] | |||
}'::jsonb; | |||
tr_full jsonb := '{ | |||
"0":0,"1":1,"2":2,"3":3,"4":4,"5":5,"6":6,"7":7,"8":8, | |||
"9":9,"a":10,"b":11,"c":12,"d":13,"e":14,"f":15 | |||
}'::jsonb; | |||
blk text[]; | |||
bits varbit; | |||
n int; | |||
i char; | |||
ret varbit; | |||
BEGIN | |||
ret = ''; | |||
blk := regexp_match(p_val,'^([0-9a-f]*)([ghjkmnp-tvzy])?$'); | |||
IF blk[1] >'' THEN | |||
FOREACH i IN ARRAY regexp_split_to_array(blk[1],'') LOOP | |||
ret := ret || CASE p_base | |||
WHEN 16 THEN (tr_full->>i)::int::bit(4)::varbit | |||
WHEN 8 THEN (tr_full->>i)::int::bit(3)::varbit | |||
WHEN 4 THEN (tr_full->>i)::int::bit(2)::varbit | |||
END; | |||
END LOOP; | |||
END IF; | |||
IF blk[2] >'' THEN | |||
n = (tr_hdig->blk[2]->>0)::int; | |||
ret := ret || CASE n | |||
WHEN 1 THEN (tr_hdig->blk[2]->>1)::int::bit(1)::varbit | |||
WHEN 2 THEN (tr_hdig->blk[2]->>1)::int::bit(2)::varbit | |||
WHEN 3 THEN (tr_hdig->blk[2]->>1)::int::bit(3)::varbit | |||
END; | |||
END IF; | |||
RETURN ret; | |||
END | |||
$f$ LANGUAGE PLpgSQL IMMUTABLE; | |||
</syntaxhighlight> | |||
== Ilustrando em geocódigos == | == Ilustrando em geocódigos == |