Olá pessoal…
Hoje vou mostrar uma rotina que foi desenvolvida, que ao informar algum conteúdo especial em algum campo, esse conteúdo é retirado (como acentos e outros caracteres).
Primeiramente, quero agradecer ao meu amigo Rafael Achôa, que me ajudou no desenvolvimento da rotina.
Foram desenvolvidas 2 rotinas, a primeira que substitui realmente os caracteres, a u_zLimpaEsp(), que pode ser colocada na validação de usuário de qualquer campo.
A segunda rotina, é uma rotina de atualização de campos, a u_zCarEspec(), que ao mesmo tempo, desabilita o parâmetro MV_ACENTO, e em seguida atualiza vários campos para não aceitar os caracteres especiais (adicionando o u_zLimpaEsp). Essa rotina pode ser executada no Fórmulas.
Abaixo o código fonte desenvolvido.
//Bibliotecas
#Include "Protheus.ch"
/*/{Protheus.doc} zLimpaEsp
Função que limpa os caracteres especiais dentro de um campo
@type function
@author Atilio / Achoa
@since 25/04/2016
@version 1.0
@param lEndereco, Lógico, Define se o campo é endereço (caso sim, o traço e vírgula serão ignorados)
@example
u_zLimpaEsp()
/*/
User Function zLimpaEsp(lEndereco)
Local aArea := GetArea()
Local cCampo := ReadVar()
Local cConteudo := &(cCampo)
Local nTamOrig := Len(cConteudo)
Default lEndereco := .F.
//Retirando caracteres
cConteudo := StrTran(cConteudo, "'", "")
cConteudo := StrTran(cConteudo, "#", "")
cConteudo := StrTran(cConteudo, "%", "")
cConteudo := StrTran(cConteudo, "*", "")
cConteudo := StrTran(cConteudo, "&", "E")
cConteudo := StrTran(cConteudo, ">", "")
cConteudo := StrTran(cConteudo, "<", "")
cConteudo := StrTran(cConteudo, "!", "")
cConteudo := StrTran(cConteudo, "@", "")
cConteudo := StrTran(cConteudo, "$", "")
cConteudo := StrTran(cConteudo, "(", "")
cConteudo := StrTran(cConteudo, ")", "")
cConteudo := StrTran(cConteudo, "_", "")
cConteudo := StrTran(cConteudo, "=", "")
cConteudo := StrTran(cConteudo, "+", "")
cConteudo := StrTran(cConteudo, "{", "")
cConteudo := StrTran(cConteudo, "}", "")
cConteudo := StrTran(cConteudo, "[", "")
cConteudo := StrTran(cConteudo, "]", "")
cConteudo := StrTran(cConteudo, "/", "")
cConteudo := StrTran(cConteudo, "?", "")
cConteudo := StrTran(cConteudo, ".", "")
cConteudo := StrTran(cConteudo, "\", "")
cConteudo := StrTran(cConteudo, "|", "")
cConteudo := StrTran(cConteudo, ":", "")
cConteudo := StrTran(cConteudo, ";", "")
cConteudo := StrTran(cConteudo, '"', '')
cConteudo := StrTran(cConteudo, '°', '')
cConteudo := StrTran(cConteudo, 'ª', '')
//Se não for endereço, retira também o - e a ,
If !lEndereco
cConteudo := StrTran(cConteudo, ",", "")
cConteudo := StrTran(cConteudo, "-", "")
EndIf
//Adicionando os espaços a direita
cConteudo := Alltrim(cConteudo)
cConteudo += Space(nTamOrig - Len(cConteudo))
//Definindo o conteúdo do campo
&(cCampo+" := '"+cConteudo+"' ")
RestArea(aArea)
Return .T.
/*/{Protheus.doc} zCarEspec
Script para atualização de campos que terão sua validação de usuário alterada
@type function
@author Atilio
@since 25/04/2016
@version 1.0
/*/
User Function zCarEspec()
Local aArea := GetArea()
Local aTexto := {}
Local aBotoes := {}
Local lContinua := .F.
//Adicionando textos da rotina
aAdd(aTexto, 'Esta rotina tem por objetivo atualizar campos para ')
aAdd(aTexto, 'não aceitar caracteres especiais em cadastros.')
aAdd(aTexto, '')
aAdd(aTexto, 'Será atualizado:')
aAdd(aTexto, 'Parâmetro MV_ACENTO')
aAdd(aTexto, 'Tabelas SA1, SA2, SA4 e SB1')
//Adicionando os botões da rotina
aAdd(aBotoes, {1, .T., {|| lContinua := .T., FechaBatch()}})
aAdd(aBotoes, {2, .T., {|| lContinua := .F., FechaBatch()}})
//Mostra o batch esperando interação do usuário
FormBatch("Atualização de campos", aTexto, aBotoes)
//Se for para continuar o processamento
If lContinua
Processa({|| fAtualiza()}, "Processando...")
EndIf
RestArea(aArea)
Return
/*---------------------------------------------------------------------*
| Func: fAtualiza |
| Autor: Daniel Atilio |
| Data: 25/04/2016 |
| Desc: Função que atualiza os dados |
*---------------------------------------------------------------------*/
Static Function fAtualiza()
Local aAreaX3 := SX3->(GetArea())
Local aCampos := {}
Local aCamposEnd := {}
Local cValidUsr := ""
Local nAtual := 0
DbSelectArea('SX3')
SX3->(dbSetOrder(2)) // X3_CAMPO
ProcRegua(3)
//Campos normais
aAdd(aCampos, 'A1_NOME')
aAdd(aCampos, 'A1_NREDUZ')
aAdd(aCampos, 'A1_BAIRRO')
aAdd(aCampos, 'A1_MUN')
aAdd(aCampos, 'A2_NOME')
aAdd(aCampos, 'A2_NREDUZ')
aAdd(aCampos, 'A2_BAIRRO')
aAdd(aCampos, 'A2_MUN')
aAdd(aCampos, 'A4_NOME')
aAdd(aCampos, 'A4_NREDUZ')
aAdd(aCampos, 'A4_BAIRRO')
aAdd(aCampos, 'B1_DESC')
//Campos de endereço
aAdd(aCamposEnd, 'A1_END')
aAdd(aCamposEnd, 'A2_END')
aAdd(aCamposEnd, 'A4_END')
//Atualiza o MV_ACENTO para não aceitar acentuação no sistema
IncProc("Atualizando parâmetro...")
PutMV('MV_ACENTO', 'N')
//Percorrendo os campos normais
IncProc("Atualizando campos normais...")
SX3->(DbGoTop())
For nAtual := 1 To Len(aCampos)
//Se conseguir posicionar
If SX3->(DbSeek(aCampos[nAtual]))
cValidUsr := Alltrim(SX3->X3_VLDUSER)
//Se já tiver, pula o campo
If "U_ZLIMPAESP" $ Upper(cValidUsr)
nAtual++
Loop
EndIf
//Se tiver conteúdo, adiciona .And. no valid
If !Empty(cValidUsr)
cValidUsr += ".And."
Endif
//Definindo a expressão
cValidUsr += "u_zLimpaEsp()"
//Atualiza no banco
RecLock('SX3', .F.)
X3_VLDUSER := cValidUsr
SX3->(MsUnlock())
EndIf
Next
//Percorrendo os campos de endereço
IncProc("Atualizando campos de endereço...")
SX3->(DbGoTop())
For nAtual := 1 To Len(aCamposEnd)
//Se conseguir posicionar
If SX3->(DbSeek(aCamposEnd[nAtual]))
cValidUsr := Alltrim(SX3->X3_VLDUSER)
//Se já tiver, pula o campo
If "U_ZLIMPAESP" $ Upper(cValidUsr)
nAtual++
Loop
EndIf
//Se tiver conteúdo, adiciona .And. no valid
If !Empty(cValidUsr)
cValidUsr += ".And."
Endif
//Definindo a expressão
cValidUsr += "u_zLimpaEsp(.T.)"
//Atualiza no banco
RecLock('SX3', .F.)
X3_VLDUSER := cValidUsr
SX3->(MsUnlock())
EndIf
Next
RestArea(aAreaX3)
Return
Bom pessoal, por hoje é só.
Abraços e até a próxima.

Top, Atílio!
Funcionando perfeitamente aqui na Jolie Café!
Abraços,
Ahooo Achôa san.
Um grande abraço jovem.
Valew Daniel féra como sempre, o Achôa é gente boa hem… Parabéns pelo post…
Ahooo Robs, valeu brother.
Aquele abraço.
Parabéns Atílio !
Quando se propaga conhecimento, o propagador jamais será esquecido. Continue assim, com esse espírito de compartilhar conhecimento.
Grande Carlos.
Muito obrigado jovem.
Um grande abraço.
Muito top, mas quando coloco na validação do usuario do campo B1_COD, no debug faz corretamente mas salva com espaço, teria algo a mais a ser feito?
Como o cadastro de produto foi para MVC, talvez pode ser por isso.
Tente utilizar a FWFldPut, olhe o exemplo 2 nesse link – https://terminaldeinformacao.com/knowledgebase/fwfldput/
Showwww muito bom, resolvi um problema com as APIs que alguns cadastros tinha caracteres como “” isso quebrava o meu JSON, parabéns por disponibilizar esse conhecimento.
Opa, eu que agradeço pelo comentário jovem.
Grande abraço.
Boa tarde, Alguem em 2022 conseguiu usar o fonte? deu erro na linha 19 no meu
Bom dia Tiago.
Você consegue nos disponibilizar como você testou o fonte? Se foi em um valid de usuário de campo, valid de pergunta, direto em um dialog?
Se possível nos mande um doc do word detalhando o procedimento que fez para testar.
Ficamos no aguardo.
No inicializador de usuário, como eu teria declarar lá para chamar a função?
Bom dia Caio, tudo joia?
No caso, você quer mesmo usar em um Inicializador? Pois só vai ser acionado se o usuário clicar em incluir (campo real) ou nas outras opções se for um campo virtual. Nesse artigo eu explico um pouco sobre o conceito de inicialização dos campos: https://terminaldeinformacao.com/2021/07/07/para-que-serve-e-como-criar-um-ini-padrao-de-campo/
Dito isso, essa rotina de tirar caracteres foi pensada em ser usada na validação do campo (X3_VLDUSER), onde ao usuário preencher uma informação e dar um -enter- ou -tab- automaticamente os caracteres serem alterados. Então para isso, basta você ir no campo e na Validação de Usuário, você colocar a chamada dela: u_zLimpaEsp()
Agora se realmente você tem um cenário de campo Virtual onde você precisa sempre que o usuário clicar em visualizar ou alterar, você fazer essa tratativa, ai você precisaria adaptar a rotina, para que ela não lesse do ReadVar() , mas sim do conteúdo que você esta inicializando.
Ah e se quiser também, no nosso curso de Configurador, nós explicamos sobre Contexto, Inicialização, Validação e Modo de Edição de campos nas aulas 22 a 25 – https://terminaldeinformacao.com/2022/03/14/curso-configurador-sigacfg/
Um grande abraço.