Como posso identificar a codificação do arquivo?

Projeto [x]Harbour - Compilador de código aberto compatível com o Clipper.

Moderador: Moderadores

Avatar do usuário
Jairo Maia
Moderador
Moderador
Mensagens: 2785
Registrado em: 16 Ago 2010 13:46
Localização: Campinas-SP

Como posso identificar a codificação do arquivo?

Mensagem por Jairo Maia »

Olá Pessoal,

Alguém sabe alguma forma para eu poder saber em que formato está um arquivo texto, levando-se em conta que o charset não vem identificado nele? Gostaria de saber que forma usar para saber com qual CharSet foi escrito o arquivo. Por exemplo:

ANSI - Relatório de comissões no mês de [...]
OEM - Relat¢rio de comissäes no mˆs de [...]
UTF-8 - Relatório de comissΣes no mês de [...]

Agradeço qualquer dica.
Abraços, Jairo
Harbour / Clipper 5.2e - Blinker 7
(Não respondo dúvidas por MP ou E-mail. Por favor, não encaminhe via mensagem privada ou e-mail, dúvidas que podem ser compartilhadas com todos no fórum)
Avatar do usuário
Pablo César
Usuário Nível 7
Usuário Nível 7
Mensagens: 5312
Registrado em: 31 Mai 2006 10:22
Localização: Curitiba - Paraná

Como posso identificar a codificação do arquivo?

Mensagem por Pablo César »

Olá amigo Jairo !

Achei parte das questões no código indicado pelo Leonardo em: https://pctoledo.org/forum/viewto ... gma#p51870

E achei sobre como saber se é UTF-8, em: http://www.hmgextended.com/files/CONTRI ... onvert.prg

Portanto já dá para fazer testes se realmente funciona:

Código: Selecionar todos

#include <hmg.ch>

Function Main

If ISANSI("ANSI - Relatório de comissões no mês de [...]")
   MsgInfo("É ANSI")
Endif
If ISOEM("OEM - Relat¢rio de comissäes no mˆs de [...]")
   MsgInfo("É OEM")
Endif
If ISU8("UTF-8 - Relatório de comissΣes no mês de [...]")
   MsgInfo("É UTF-8")
Endif
Return

/*

  ISU8()

  Determines whether a string contains only valid UTF-8 characters

  This function determines whether a string contains only bytes that are 
  valid in UTF-8 encoding.  It checks only that byte sequences represent code 
  points that are within the Unicode range of 0 to 1114111 (decimal) = 10FFFF 
  (hexadecimal).  It does not check whether code points within this range are 
  assigned to Unicode characters.

  Arguments:
    <cStr>      Required    String to be tested

  Returns:
    <lU8>                   Whether <cStr> contains only UTF-8 characters

*/

FUNCTION IsU8(cStr)
LOCAL lIsU8  := .Y.
LOCAL lScan  := !EMPTY(LEN(cStr))
LOCAL nPos   := 1
LOCAL nByte1 := 0
LOCAL nByte2 := 0
LOCAL nByte3 := 0
LOCAL nByte4 := 0
LOCAL nBytes := 0
LOCAL nCode  := 0
LOCAL nLen   := LEN(cStr)

WHILE lScan
  nByte1 := ASCPOS(cStr, nPos)
  DO CASE
  CASE nByte1 >= 0x00 .AND. nByte1 <= 0x7F
    nBytes := 1
  CASE nByte1 >= 0xC2 .AND. nByte1 <= 0xDF
    nBytes := 2
    nByte2 := ASCPOS(cStr, nPos + 1)
    IF !(nByte2 >= 0x80 .AND. nByte2 <= 0xBF)
      lIsU8 := .N.
    END
  CASE nByte1 == 0xE0
    nBytes := 3
    nByte2 := ASCPOS(cStr, nPos + 1)
    nByte3 := ASCPOS(cStr, nPos + 2)
    IF !(nByte2 >= 0xA0 .AND. nByte2 <= 0xBF .AND. ;
      nByte3 >= 0x80 .AND. nByte3 <= 0xBF)
      lIsU8 := .N.
    END
  CASE nByte1 >= 0xE1 .AND. nByte1 <= 0xEF
    nBytes := 3
    nByte2 := ASCPOS(cStr, nPos + 1)
    nByte3 := ASCPOS(cStr, nPos + 2)
    IF !(nByte2 >= 0x80 .AND. nByte2 <= 0xBF .AND. ;
      nByte3 >= 0x80 .AND. nByte3 <= 0xBF)
      lIsU8 := .N.
    END
  CASE nByte1 >= 0xF0 .AND. nByte1 <= 0xF4
    nBytes := 4
    nByte2 := ASCPOS(cStr, nPos + 1)
    nByte3 := ASCPOS(cStr, nPos + 2)
    nByte4 := ASCPOS(cStr, nPos + 3)
    IF !( ;
      nByte2 >= 0x80 .AND. nByte2 <= 0xBF .AND. ;
      nByte3 >= 0x80 .AND. nByte3 <= 0xBF .AND. ;
      nByte4 >= 0x80 .AND. nByte4 <= 0xBF)
      lIsU8 := .N.
    END
  OTHERWISE
    lIsU8 := .N.
  END
  nPos  += nBytes
  lScan := lIsU8 .AND. nPos <= nLen
END
RETURN lIsU8 // IsU8

#pragma BeginDump
#include "hbapi.h"
#include "windows.h"

HB_FUNC( ISANSI)
{
   LPBYTE pMyString;
   WORD  pos;
   BOOL  bRetorno = FALSE;
   pos = 0;
   pMyString = ( LPBYTE ) hb_parc( 1 );
   while( pos < (WORD) hb_parclen( 1 ) && ! bRetorno )
   {
      bRetorno = ( pMyString[ pos ] >= 224 && pMyString[ pos ] <= 255 ) || pMyString[ pos ] == 128;
      pos++;
   }
   hb_retl( bRetorno );
}

HB_FUNC( ISOEM )
{
    LPBYTE pMyString;
    WORD  pos;
    BOOL  bRetorno = FALSE;
    pos = 0;
    pMyString = ( LPBYTE ) hb_parc( 1 );
    while( pos < (WORD) hb_parclen( 1 ) && ! bRetorno )
    {
       bRetorno = pMyString[ pos ] > 128 && pMyString[ pos ] <= 168;
       pos++;
    }
    hb_retl( bRetorno );
}
#pragma EndDump
Um clip-abraço !

Pablo César Arrascaeta
Compartilhe suas dúvidas e soluções com todos os colegas aqui do fórum.
Evite enviar as dúvidas técnicas por MPs ou eMails, assim todos iremos beneficiar-nos.
lugab
Colaborador
Colaborador
Mensagens: 843
Registrado em: 19 Mai 2009 15:58

Como posso identificar a codificação do arquivo?

Mensagem por lugab »

Aproveito a similaridade do tema, para perguntar aos amigos o seguinte:

Conhecem e poderiam compartilhar conosco um código fonte - para compilarmos com nossas aplicações em (X)harbour - , onde a gente possa enviar um arquivo .TXT (de qq tamanho e de qq numero de linhas) e recebê-lo de volta já no formato UTF8 ?

Atualmente eu venho usando via RUN um executável, chamado STR2UTF8.EXE, que faz exatamente isso, porém, parece que é de 16 bits e as vezes ele executa normalmente e as vezes, não.

O "Run STR2UTF8.EXE arquivo.txt" le o "arquivo.txt" e gera o "arquivo8.txt" já no formato UTF8

Grato,

Gabriel
lugab
Avatar do usuário
Jairo Maia
Moderador
Moderador
Mensagens: 2785
Registrado em: 16 Ago 2010 13:46
Localização: Campinas-SP

Como posso identificar a codificação do arquivo?

Mensagem por Jairo Maia »

Olá meu amigo Pablo,

Valeu! Pela mnhã vou fazer os testes, mas acho que vai resolver. Puxa vida... acho que encerrei horas de quebra cabeça sobre essa questão.

De qualquer forma, posto o resultado assim que concluir os testes. Muito obrigado.
Abraços, Jairo
Harbour / Clipper 5.2e - Blinker 7
(Não respondo dúvidas por MP ou E-mail. Por favor, não encaminhe via mensagem privada ou e-mail, dúvidas que podem ser compartilhadas com todos no fórum)
Avatar do usuário
Jairo Maia
Moderador
Moderador
Mensagens: 2785
Registrado em: 16 Ago 2010 13:46
Localização: Campinas-SP

Como posso identificar a codificação do arquivo?

Mensagem por Jairo Maia »

Olá Gabriel,

Tente com Hb_StrToUTF8( cString)

Exemplo:

Código: Selecionar todos

Function Main()
 Local cBuffer := Hb_MemoRead( cArquivo.txt )
 cBuffer := Hb_StrToUTF8( cBuffer )
 Hb_MemoWrit( "cNovoArquivo.Ext", cBuffer )
Return Nil
Abraços, Jairo
Harbour / Clipper 5.2e - Blinker 7
(Não respondo dúvidas por MP ou E-mail. Por favor, não encaminhe via mensagem privada ou e-mail, dúvidas que podem ser compartilhadas com todos no fórum)
lugab
Colaborador
Colaborador
Mensagens: 843
Registrado em: 19 Mai 2009 15:58

Como posso identificar a codificação do arquivo?

Mensagem por lugab »

Valeu, Jairo.

Mas, vc sabe qual os nomes em Xharbour , das funções:

Hb_MemoRead()
Hb_StrToUTF8()
Hb_MemoWrit( )

Vou testar e te dou um retorno.

Grato,

Gabriel
lugab
Avatar do usuário
Jairo Maia
Moderador
Moderador
Mensagens: 2785
Registrado em: 16 Ago 2010 13:46
Localização: Campinas-SP

Como posso identificar a codificação do arquivo?

Mensagem por Jairo Maia »

Olá Gabriel.

Em xHarbour:
Hb_StrToUTF8( cString ) // converte o formato OEM para UTF-8
Hb_UTF8ToStr( cString ) // converte o formato UTF-8 para OEM

Nota: Pode ocorrer anomalia se cString estiver em ANSI.

Já as funções Hb_MemoRead() e Hb_MemoWrit(), caso não seja assim, tenho certeza que no xHarbour estão como MemoRead() e MemoWrit(), como no Clipper, e em xHarbour e Harbour, o limite de tamanho para carregar o arquivo é a capacidade de memória.

PS: Não sei qual versão do xHarbour você usa, o que sei é que no Harbour, o suporte para UTF-8 está disponível a partir da versão 2.1. Ocorre que recentemente vi um post do colega Leonardo citando as funções acima para UTF-8 em xHarbour, mas não sei dizer a partir de qual versão está disponível no xHarbour.
Abraços, Jairo
Harbour / Clipper 5.2e - Blinker 7
(Não respondo dúvidas por MP ou E-mail. Por favor, não encaminhe via mensagem privada ou e-mail, dúvidas que podem ser compartilhadas com todos no fórum)
Avatar do usuário
Pablo César
Usuário Nível 7
Usuário Nível 7
Mensagens: 5312
Registrado em: 31 Mai 2006 10:22
Localização: Curitiba - Paraná

Como posso identificar a codificação do arquivo?

Mensagem por Pablo César »

Caro Jairo, deparei com um erro quando refiz o código/exemplo desta forma:

Código: Selecionar todos

#include <hmg.ch>

REQUEST HB_CODEPAGE_PTISO
REQUEST HB_CODEPAGE_PT850

Function Main()
Local aText:={}, cMsg:="", i

SET LANGUAGE TO PORTUGUESE
SET CODEPAGE TO PORTUGUESE

Aadd(aText,"ANSI - Relatório de comissões no mês de [...]")
Aadd(aText,"OEM - Relat¢rio de comissäes no mˆs de [...]")
Aadd(aText,"UTF-8 - Relatório de comissΣes no mês de [...]")

For i=1 to 3
    If ISANSI(aText[i])
       cMsg:=cMsg+"É ANSI: "+aText[i]+CRLF
    Else
	   cMsg:=cMsg+"NÃO é ANSI: "+aText[i]+CRLF
    Endif
    
	If ISOEM(aText[i])
       cMsg:=cMsg+"É OEM: "+aText[i]+CRLF
	Else
	   cMsg:=cMsg+"NÃO é OEM: "+aText[i]+CRLF
    Endif
	
    If ISU8(aText[i])
       cMsg:=cMsg+"É UTF-8: "+aText[i]+CRLF
	Else
	   cMsg:=cMsg+"NÃO é UTF-8: "+aText[i]+CRLF
    Endif
	
	cMsg:=cMsg+CRLF
Next
MsgInfo(cMsg)
Return

/*

  ISU8()

  Determines whether a string contains only valid UTF-8 characters

  This function determines whether a string contains only bytes that are 
  valid in UTF-8 encoding.  It checks only that byte sequences represent code 
  points that are within the Unicode range of 0 to 1114111 (decimal) = 10FFFF 
  (hexadecimal).  It does not check whether code points within this range are 
  assigned to Unicode characters.

  Arguments:
    <cStr>      Required    String to be tested

  Returns:
    <lU8>                   Whether <cStr> contains only UTF-8 characters

*/

FUNCTION IsU8(cStr)
LOCAL lIsU8  := .Y.
LOCAL lScan  := !EMPTY(LEN(cStr))
LOCAL nPos   := 1
LOCAL nByte1 := 0
LOCAL nByte2 := 0
LOCAL nByte3 := 0
LOCAL nByte4 := 0
LOCAL nBytes := 0
LOCAL nCode  := 0
LOCAL nLen   := LEN(cStr)

WHILE lScan
  nByte1 := ASCPOS(cStr, nPos)
  DO CASE
  CASE nByte1 >= 0x00 .AND. nByte1 <= 0x7F
    nBytes := 1
  CASE nByte1 >= 0xC2 .AND. nByte1 <= 0xDF
    nBytes := 2
    nByte2 := ASCPOS(cStr, nPos + 1)
    IF !(nByte2 >= 0x80 .AND. nByte2 <= 0xBF)
      lIsU8 := .N.
    END
  CASE nByte1 == 0xE0
    nBytes := 3
    nByte2 := ASCPOS(cStr, nPos + 1)
    nByte3 := ASCPOS(cStr, nPos + 2)
    IF !(nByte2 >= 0xA0 .AND. nByte2 <= 0xBF .AND. ;
      nByte3 >= 0x80 .AND. nByte3 <= 0xBF)
      lIsU8 := .N.
    END
  CASE nByte1 >= 0xE1 .AND. nByte1 <= 0xEF
    nBytes := 3
    nByte2 := ASCPOS(cStr, nPos + 1)
    nByte3 := ASCPOS(cStr, nPos + 2)
    IF !(nByte2 >= 0x80 .AND. nByte2 <= 0xBF .AND. ;
      nByte3 >= 0x80 .AND. nByte3 <= 0xBF)
      lIsU8 := .N.
    END
  CASE nByte1 >= 0xF0 .AND. nByte1 <= 0xF4
    nBytes := 4
    nByte2 := ASCPOS(cStr, nPos + 1)
    nByte3 := ASCPOS(cStr, nPos + 2)
    nByte4 := ASCPOS(cStr, nPos + 3)
    IF !( ;
      nByte2 >= 0x80 .AND. nByte2 <= 0xBF .AND. ;
      nByte3 >= 0x80 .AND. nByte3 <= 0xBF .AND. ;
      nByte4 >= 0x80 .AND. nByte4 <= 0xBF)
      lIsU8 := .N.
    END
  OTHERWISE
    lIsU8 := .N.
  END
  nPos  += nBytes
  lScan := lIsU8 .AND. nPos <= nLen
END
RETURN lIsU8 // IsU8

#pragma BeginDump

#include "hbapi.h"
#include "windows.h"

HB_FUNC( ISANSI)
{
   LPBYTE pString = ( LPBYTE ) hb_parc( 1 );
   WORD  w = 0, wLen = hb_parclen( 1 );
   BOOL  bAnsi = FALSE;

   while( w < wLen && ! bAnsi )
   {
      bAnsi = ( pString[ w ] >= 224 && pString[ w ] <= 255 ) || pString[ w ] == 128;
      w++;
   }

   hb_retl( bAnsi );
}

HB_FUNC( ISOEM )
{
   LPBYTE pString = ( LPBYTE ) hb_parc( 1 );
   WORD  w = 0, wLen = hb_parclen( 1 );
   BOOL  bOem = FALSE;

   while( w < wLen && ! bOem )
   {
      bOem = pString[ w ] > 128 && pString[ w ] <= 168;
      w++;
   }

   hb_retl( bOem );
}

#pragma EndDump
Até refiz as funções em C com outro nome de variáveis para saber se era isso o que está incidindo. Pois nas primeiras linhas está mostrando normal mas as seguintes não. Veja:
Tela59.PNG
Seria erro no código quando este retorna .F. em alguma das funções ? O quê poderia estar errado ?
Um clip-abraço !

Pablo César Arrascaeta
Compartilhe suas dúvidas e soluções com todos os colegas aqui do fórum.
Evite enviar as dúvidas técnicas por MPs ou eMails, assim todos iremos beneficiar-nos.
Avatar do usuário
Jairo Maia
Moderador
Moderador
Mensagens: 2785
Registrado em: 16 Ago 2010 13:46
Localização: Campinas-SP

Como posso identificar a codificação do arquivo?

Mensagem por Jairo Maia »

Olá Pablo,
Pablo César escreveu:Seria erro no código quando este retorna .F. em alguma das funções ? O quê poderia estar errado ? :D
Desculpe colega, mas não pude deixar de rir de seu lapso... hehehe...

Não há nada errado na apresentação de seu exemplo. Veja que o primeiro passo está em ANSI, então se apresenta corretamente com a codificação PT850. O segundo está em OEM e o terceiro em UTF-8. Os dois últimos só ficarão corretos se forem convertidos para ANSI, pois você está compilando em GUI. Se compilar em Modo Console, o bloco que aparecerá correto é o bloco que está em OEM.

Mas reportando sobre os exemplos que você passou, a função ISANSI() não funciona. Retorna sempre .T., e a função OEM retorna .T. quando o texto é em UTF-8, mas retorna .F. quando o texto é ANSI.

Assim, todos os testes resultaram corretos na função abaixo, e necessariamente nessa ordem de checagem: UTF-8 e depois se é OEM. Assim, como a função ISANSI() não funciona, se o texto não for UTF-8 nem OEM, considero como ANSI. Funcionou corretamente:

Código: Selecionar todos

Function IdCharSet( cString )
  Local cCharSet

  If ISU8( cString )
    cCharSet := "UTF-8"
  ElseIf ISOEM( cString )
    cCharSet := "OEM"
  Else
   cCharSet := "ANSI"
  Endif

Return ( cCharSet )
Acredito que as funções possam ser aprimoradas, mas considero que o problema está resolvido após vários testes.

Pablo, novamente muito obrigado por sua ajuda e dedicação ao fórum. Valeu mesmo!!!
Abraços, Jairo
Harbour / Clipper 5.2e - Blinker 7
(Não respondo dúvidas por MP ou E-mail. Por favor, não encaminhe via mensagem privada ou e-mail, dúvidas que podem ser compartilhadas com todos no fórum)
Avatar do usuário
Pablo César
Usuário Nível 7
Usuário Nível 7
Mensagens: 5312
Registrado em: 31 Mai 2006 10:22
Localização: Curitiba - Paraná

Como posso identificar a codificação do arquivo?

Mensagem por Pablo César »

Entendi nada ! Nem da causa do seu riso nem a explicação. Deve ter sido porque fiquei injuriado... kkkk se lá vou analisar mais tarde tudo o que você disse...
Um clip-abraço !

Pablo César Arrascaeta
Compartilhe suas dúvidas e soluções com todos os colegas aqui do fórum.
Evite enviar as dúvidas técnicas por MPs ou eMails, assim todos iremos beneficiar-nos.
lugab
Colaborador
Colaborador
Mensagens: 843
Registrado em: 19 Mai 2009 15:58

Como posso identificar a codificação do arquivo?

Mensagem por lugab »

Certo, Jário

Os nomes " MemoRead() e Memowrit() " funcionaram beleza, em XHarbour

Mas o " Hb_StrToUTF8( ) " , não

Tentei Xharbour 1.00 e 1.10 e nada do Hb_StrToUTF8( ) passar

A mensagem de erro é: "unresolved external"
lugab
Avatar do usuário
Pablo César
Usuário Nível 7
Usuário Nível 7
Mensagens: 5312
Registrado em: 31 Mai 2006 10:22
Localização: Curitiba - Paraná

Como posso identificar a codificação do arquivo?

Mensagem por Pablo César »

Gabriel, por quê você insiste em xHarbour, mude pra Harbour !

Essas funções são para Harbour.
Um clip-abraço !

Pablo César Arrascaeta
Compartilhe suas dúvidas e soluções com todos os colegas aqui do fórum.
Evite enviar as dúvidas técnicas por MPs ou eMails, assim todos iremos beneficiar-nos.
Avatar do usuário
Jairo Maia
Moderador
Moderador
Mensagens: 2785
Registrado em: 16 Ago 2010 13:46
Localização: Campinas-SP

Como posso identificar a codificação do arquivo?

Mensagem por Jairo Maia »

Olá Gabriel,

Fiz um teste com xHarbour 1.2.1 usando essas funções, e todas foram encontradas:

Código: Selecionar todos

Hb_MemoRead( cFile )
Hb_MemoWrit( cNewFile, cBuffer )
Hb_StrToUTF8( cString )
Hb_UTF8ToStr( cString )
Obstante a sugestão do Pablo, você não pode atuaizar o xHarbour para a versão 1.2.1? O xHarbour que tenho instalado é a versão disponibilizada pelo Leonardo na seção downloads.
Abraços, Jairo
Harbour / Clipper 5.2e - Blinker 7
(Não respondo dúvidas por MP ou E-mail. Por favor, não encaminhe via mensagem privada ou e-mail, dúvidas que podem ser compartilhadas com todos no fórum)
lugab
Colaborador
Colaborador
Mensagens: 843
Registrado em: 19 Mai 2009 15:58

Como posso identificar a codificação do arquivo?

Mensagem por lugab »

Valeu Jairo, valeu Pablo.

thanks, by attention

Vou fazer os testes
lugab
Imatech
Usuário Nível 3
Usuário Nível 3
Mensagens: 350
Registrado em: 24 Ago 2010 23:48
Localização: Goiânia-GO

Como posso identificar a codificação do arquivo?

Mensagem por Imatech »

Nova função do harbour:

Código: Selecionar todos

hb_cdpIsUTF8( Memoread( cFile ) )
M., Ronaldo

by: IMATECH

IMATION TECNOLOGIA
Responder