Página 1 de 2

Como posso identificar a codificação do arquivo?

Enviado: 26 Out 2012 12:29
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.

Como posso identificar a codificação do arquivo?

Enviado: 26 Out 2012 14:26
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

Como posso identificar a codificação do arquivo?

Enviado: 26 Out 2012 19:34
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

Como posso identificar a codificação do arquivo?

Enviado: 26 Out 2012 20:01
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.

Como posso identificar a codificação do arquivo?

Enviado: 26 Out 2012 20:06
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

Como posso identificar a codificação do arquivo?

Enviado: 27 Out 2012 03:37
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

Como posso identificar a codificação do arquivo?

Enviado: 27 Out 2012 08:20
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.

Como posso identificar a codificação do arquivo?

Enviado: 27 Out 2012 10:31
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 ?

Como posso identificar a codificação do arquivo?

Enviado: 27 Out 2012 12:02
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!!!

Como posso identificar a codificação do arquivo?

Enviado: 27 Out 2012 12:28
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...

Como posso identificar a codificação do arquivo?

Enviado: 27 Out 2012 17:19
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"

Como posso identificar a codificação do arquivo?

Enviado: 27 Out 2012 19:45
por Pablo César
Gabriel, por quê você insiste em xHarbour, mude pra Harbour !

Essas funções são para Harbour.

Como posso identificar a codificação do arquivo?

Enviado: 28 Out 2012 10:05
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.

Como posso identificar a codificação do arquivo?

Enviado: 28 Out 2012 13:45
por lugab
Valeu Jairo, valeu Pablo.

thanks, by attention

Vou fazer os testes

Como posso identificar a codificação do arquivo?

Enviado: 28 Out 2012 18:15
por Imatech
Nova função do harbour:

Código: Selecionar todos

hb_cdpIsUTF8( Memoread( cFile ) )