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 ==