Olá pessoal…
Hoje vou mostrar uma rotina desenvolvida para converter valores gerados pelo Soma1 (como por exemplo, após o 99, vir o 9A, depois o 9B, 9C, 9D até chegar no ZZ).
Foram desenvolvidas duas rotinas, a primeira converte 100% dos casos, porém é bem mais demorada, pois é feito um While, percorrendo até chegar no valor do soma1.
A segunda, pelos testes realizados, converte 100% quando o valor tem 1 posição ou duas (ou seja, no tamanho máximo de “ZZ”), a partir de 3 posições, o fator fica impreciso no valor de AB0, pois não consegui chegar em um fator de conversão exato.
Abaixo o código desenvolvido com as duas funções.
//Bibliotecas #Include "Protheus.ch" /*/{Protheus.doc} zCnvSoma1 Função de conversão do Soma1 @type function @author Atilio @since 03/08/2016 @version 1.0 @param cValor, character, Valor do Soma1 @return nValConv, Valor convertido @example u_zCnvSoma1("ZZZ") /*/ User Function zCnvSoma1(cValor) Local aArea := GetArea() Local nValConv := 0 Local cAtual := "" Default cValor := "0" //Definindo o atual como 0 cAtual := StrZero(0, Len(cValor)) cAtual := StrTran(cAtual, '0', '9') //Enquanto o valor atual for diferente do parâmetro While cAtual != cValor nValConv++ cAtual := Soma1(cAtual) EndDo RestArea(aArea) Return nValConv /*/{Protheus.doc} zCnvTipo2 Função para conversão do Soma1 (sem utilizar o While) @type function @author Atilio @since 03/08/2016 @version 1.0 @param cNumero, character, Valor do Soma1 @return nValor, Valor Convertido @example u_zCnvSoma1("ZZ") @obs Essa função não foi finalizada 100%! Não foi encontrado um fator exato de conversão, em testes realizados, com valores de tamanho 1 e 2, a função funciona perfeitamente (por exemplo, A0, ZZ, Z, M9, etc), porém para valores de tamanho 3 para cima não. Para valores de tamanho 1, a rotina funciona Para valores de tamanho 2, a rotina funciona Para valores de tamanho 3, a inconsistência começa partir do AB0 (após o AAZ) - 2357 registros Para valores de tamanho 4, a inconsistência começa partir do 9AB0 (após o 9AAZ) - 11356 registros /*/ User Function zCnvTipo2(cNumero) Local aArea := GetArea() Local nValor := 0 Local lSoNumero := .T. Local nAtual := 0 Local cAscii := "" Local nPosIni := 0 Local cCaract := "" Local nValAux := 0 Local cZeros := "" Local cAscii := "" cNumero := Upper(cNumero) //Percorre os valores For nAtual := 1 To Len(cNumero) cCaract := SubStr(cNumero, nAtual, 1) //Se tiver alguma letra no numero If cCaract $ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" If nPosIni == 0 nPosIni := nAtual EndIf lSoNumero := .F. Exit EndIf Next //Se tiver somente numero, converte com Val If lSoNumero nValor := Val(cNumero) Else nValor := 0 //Percorre os valores For nAtual := 1 To Len(cNumero) cCaract := SubStr(cNumero, nAtual, 1) cZeros := Replicate("0", Len(cNumero)-nAtual) //Se tiver alguma letra no numero If cCaract $ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" cAscii := cValToChar(Asc(cCaract) - 64 + 9) //Se for a partir da segunda posição e não for a última If nAtual > nPosIni .And. nAtual != Len(cNumero) nValAux := Val(cAscii + cZeros) + Iif(nAtual != Len(cNumero), 26 * (Asc(cCaract) - 64), 0) nValAux *= Val(cAscii) nValAux += (26 + Val(cAscii)) nValor += nValAux Else nValor += Val(cAscii + cZeros) + Iif(nAtual != Len(cNumero), 26 * (Asc(cCaract) - 64), 0) EndIf //Se for somente números Else //Se for a partir da segunda posição e não for a última If nAtual > nPosIni .And. nAtual != Len(cNumero) nValor += Val(cCaract + cZeros) + (36 * 26) + (26*Val(cCaract)) Else nValor += Val(cCaract + cZeros) EndIf EndIf Next EndIf RestArea(aArea) Return nValor
Bom pessoal, por hoje é só.
Abraços e até a próxima.
Existe a função DecodSoma1 que faz isso e é muito rápido.
Opa, valeu pelo adendo Gustavo, realmente não conhecia essa.
Pode ser que a rotina seja nova, criada após 2016 (ano que publiquei esse artigo).
Grande abraço.
Danilo, segue uma contribuição, pois já me servi várias vezes dos seus exemplos.
Não achei documentação sobre o DecodSoma1, mas ele não serviu no momento, pois não funcionou como eu esperava, ao passar uma string com 2 dígitos, não somou como no Soma1, talvez tenha algum parâmetro. Bem o Soma1, até que atenderia, mas não gostei da sequência dele após o 99, é usado de 9A a 9Z, porque não usar também para 00 a 0Z, 10 a 1Z…, foi o que fiz com as funções abaixo, assim somando os dígitos 0 a 9 e A a Z, temos 36, usando 2 dígitos, 36 X 36 = 1296 combinações, considerando o ’00’:
…
cSquenc := ’00’
cSquenc := fXSoma1(cSequenc)
…
//#############################################################################
// Função: fXSoma1 Autor: José Murilo: 13/10/2020
// Descrição: Fornecer sequência alfanumérica com os dígitos 0 a 9 e A a Z
//—————————————————————————–
// ASCII 048 a 057 números 0 – 9
// ASCII 065 a 090 letras A – Z maiúsculas
// A vantagem sobre o Soma1 é que podemos ter até 1296 combinações contra 1035,
// usando apenas 2 dígitos. 00 a 0Z, 10 a 1Z, 20 a 2Z, 30 a 3Z…
//#############################################################################
static function fXSoma1(pcNum)
Local cRet as character
Local aNum as array
aNum := {substr(pcNum,1,1), substr(pcNum,2,1)}
if aNum[2] == ‘Z’
aNum[1] := fXPrxDig(aNum[1])
aNum[2] := fXPrxDig(aNum[2])
else
aNum[2] := fXPrxDig(aNum[2])
endif
cRet := aNum[1] + aNum[2]
return(cRet)
//#############################################################################
// Função…: fXPrxDig Autor: José Murilo: 13/10/2020
// Descrição: Retorna o próximo dígito da sequência alfanumérica com os dígitos.
// 0 a 9 e A a Z
//—————————————————————————–
// ASCII 048 a 057 números 0 – 9
// ASCII 065 a 090 letras A – Z maiúsculas
//#############################################################################
static function fXPrxDig(pcDig)
Local cRet as character
if pcDig == ‘9’
cRet := ‘A’
elseif pcDig == ‘Z’
cRet := ‘0’
else
cRet := chr(asc(pcDig)+1)
endif
return(cRet)
Abraços, obrigado por compartilhar e parabéns pelo trabalho no blog.
Opa, grande José.
Obrigado pelo comentário e feedback jovem.
Pode apostar que sua contribuição será de grande valia.
Abração e obrigado mais uma vez.
“Futucando” alguns fontes antigos da LIB, encontrei a função RetAsc() que é usada nas rotinas que convertem esse tipo de campo nos grids:
Sintaxe: RetAsc(cString, nTamanho, lVolta) onde lVolta == .T. faz o processo contrário (numero para letra)
Opa, obrigado pelo comentário e contribuição jovem.
Grande abraço.