Vamos desvendar o conceito de Hash! Mas antes, é essencial entender o que é um array. Um array é composto de elementos, um hash também.
O que muda entre um array e um hash é basicamente o endereço (key) do elemento: com Array é um número enquanto que com hash é uma palavra (string). Portanto, hash é um array com chaves não-numéricas.
Essa palavra é chamada de key string ou palavra-chave ou simplesmente key, chave, que é o "endereço" do elemento.
Portanto, você precisa definir a chave e o valor associado a ela. Desta feita, o Hash é similar à um array de duas colunas onde a chave é definida na esquerda e o valor na direita.
Em um hash você precisa saber a chave para obter o valor. Em um array você precisa saber a posição numérica para obter o valor.
hPESSOA := {=>}
ou
hPESSOA := HASH()
Tudo vai ficar mais claro com um exemplo! Vamos definir uma hash hPESSOA que contém 3 tipos de dados: caracter, numérico e data. Vejamos:
FUNCTION MAIN() SET DATE BRITISH hPESSOA := {"NOME" => "JOSÉ MANUEL", "IDADE" => 35, "DNASC" => CTOD("25/11/87")} // Para obter os dados desse hash e testar os tipos de dados faríamos assim: ? hPESSOA["NOME"], VALTYPE(hPESSOA["NOME"]) ? hPESSOA["IDADE"], VALTYPE(hPESSOA["IDADE"]) ? hPESSOA["DNASC"], VALTYPE(hPESSOA["DNASC"])
Resultado:
Eis um exemplo de hash com tamanho fixo e dimensões diferentes:
FUNCTION ATUCTR(cCTR) // FUNÇÃO P/ OBTER OS DADOS ATUALIZADOS DO CONTRATO hATUCTR := {"VALOR" => {"INICIAL" => EMP->CONTRATADO, "ATUAL" => 0},; "VIGENCIA" => {"INICIAL" => EMP->VIGEINI, "FINAL" => EMP->VIGEFIM, "ATUAL" => CTOD("")}; } // [...] ROTINA PARA BUSCAR O VALOR ATUAL DO CONTRATO, SE HOUVER hATUCTR["VALOR"]["ATUAL"] := TA->ATUALIZADO // [...] ROTINA PARA BUSCAR A PRORROGAÇÃO DO CONTRATO, SE HOUVER hATUCTR["VIGENCIA"]["ATUAL"] := TA->PRAZO // CASO AINDA NÃO HAJA REAJUSTE OU PRORROGAÇÃO, TAIS HASHes SERÃO VAZIOS RETURN hATUCTR // RETORNA HASH C/ DADOS
Um hash não vai aparecer tão fácil na vida real como no exemplo básico anterior. Vamos complicar um pouquinho mais agora para ficar mais realista a coisa.
O hash é usado em páginas web, web-services e estão em muitas outras linguagens de programação e costumam trazer um registro do banco de dados.
No exemplo abaixo, o X normalmente é o ID, é o número do registro, tipo um RECNO(). Vejamos então como seria esse exemplo de hash para gravar e ler dados de 3 pessoas:
FUNCTION MAIN() SET DATE BRITISH hGRUPO := { "PESSOA" => {{"NOME" => "JOSÉ MANUEL ", "IDADE"=>35, "DNASC"=>CTOD("25/11/87")}, ; {"NOME" => "JOSÉ MAMÃO ", "IDADE"=>38, "DNASC"=>CTOD("25/11/84")}, ; {"NOME" => "JOSÉ PEREIRA", "IDADE"=>32, "DNASC"=>CTOD("25/11/90")} ; } ; } ? LEN(hGRUPO["PESSOA"]) FOR X=1 TO LEN(hGRUPO["PESSOA"]) ? hGRUPO["PESSOA"][X]["NOME"], hGRUPO["PESSOA"][X]["IDADE"], hGRUPO["PESSOA"][X]["DNASC"] NEXT
Resultado:
Key é o hash. Index é o índice do elemento do hash.
Em um hash multidimensional (nested hash) a função HHASKEY() é muito relevante porque antes de tentar acessar um elemento desse hash primeiro é preciso saber se ele está presente nele senão dará erro de acesso ao array (isso mesmo, array).
Digamos que você leu um arquivo de texto com seções e campos, você pode transformar as seções num hash multidimensional ou hash aninhado (nested hash), cada seção é um hash dentro do hash. Cada campo da seção se torna um elemento desse hash. Todavia, pode ser que nem sempre apareça as mesmas seções no texto então você terá que testar sua presença com HHASKEY() antes de tentar acessar, pois se tentar acessar algo que não exista dará erro. Fiz algo assim com os retornos do ACBR, caiu como uma luva.
Esta função transforma uma variável hash da web conhecida como JSON em uma variável hash usada no [x]Harbour feita nele próprio sem necessidade de linkar nenhuma LIB.
Observe que ele usa a função StrTran() usada para substituir uma string por outra, traduzindo a sintaxe (convertendo o formato) do JSON para o HASH do [x]Harbour. Vejamos:
Function JSontoHash( cStringJson ) /*** * Converte string formato Json em Hash */ Local hJson := {=>} cStringJson := StrTran( cStringJson,':[','=>{') cStringJson := StrTran( cStringJson,'":"','" => "') cStringJson := StrTran( cStringJson,'[','{') cStringJson := StrTran( cStringJson,']','}') cStringJson := StrTran( cStringJson,'":null','"=>nil') cStringJson := StrTran( cStringJson,'":true' ,'"=>.t.' ) cStringJson := StrTran( cStringJson,'":false','"=>.f.') cStringJson := StrTran( cStringJson,'":','"=>') cStringJson := StrTran( cStringJson,"\/","/" ) hJSon := &( cStringJson ) Return hJson
Tecnicamente a função acima deve funcionar 100% das vezes, mas caso contrário tente utilizar a lib correspondente da função HB_JSONDECODE().
Harbour 3.2 e xHarbour 1.2.3 terão já prontas na instalação nativa a função acima para resolver os problemas.
// RESOLVE ACENTUAÇÃO GRÁFICA DA LINGUA PORTUGUESA #ifndef __XHARBOUR JSONCNPJ := Win_OemToAnsi(http:responseText) #else JSONCNPJ := HB_AnsiToOem(http:responseText) #endif // CONVERTE JSON PARA HASH hb_jsonDecode( JSONCNPJ, @hCNPJA )
No exemplo, pegamos a string do webservice na variável JSONCNPJ e convertemos ela em hash atribuindo à variável hCNPJA.