domingo, 14 de junho de 2009

Limpando Caracteres de Cor do IRC - Delphi e Python

Eu achei que tinha perdido isso. Vou postar pq sei que é útil pra muita gente.

Esta função para retirada dos caracteres de cor se baseia em um autômato construído para este propósito, utilizando-se dos conceitos da Máquina de Turing.

P.S.: As duas funções foram revisadas e funcionam no Delphi 2009 e Python 2.6.2.

As duas versões são licenciadas sob a licença F.A.I.L., disponível no site do blog.



Versão Original: Delphi

(*
Função para retirar caracteres de cor de strings de IRC
Eduardo Rolim(Vndmtrx) - Knal #DelphiX - [BrasNet]
www.vindemiatrix.x-br.com
*)

Uses
Contnrs; // Necessário para poder usar a classe TStack, que implementa uma
estrutura de pilha

{
Esta função para retirada dos caracteres de cor se baseia em um autômato
construído para este propósito, utilizando-se dos conceitos da Máquina de
Turing.

A Expressão pode ser entendida como: <#3 [num [num] [,[num [num]]]>
}
function TForm1.StripIRCColor(Text: String): String;

Type
TUnitCor = packed Record
Pos: Integer;
Tam: Integer;
end;

PUnitCor = ^TUnitCor;

Var
Str: String;
UnitCor: PUnitCor;
Pilha: TStack;

I, LText: Integer; //Contador para o laço For
Pos: Integer; //Armazenador para a posição do início do marcador de cor que iremos excluir
Tam: Integer; //Armazenador para o tamanho do marcador de cor
Estado: Integer; //Estado atual da máquina

begin
//Inicialização das variáveis e objetos usados na execução do autômato
Str := Text;
Pos := -1;
Tam := -1;
Estado := 1;
LText := Length(Str);
Pilha := TStack.Create;

//Início da execução do Autômato
//For I := 1 to Length(Str) do begin
I := 1;
While (I <= LText) OR (Estado <> 1) do begin
Case Estado of
1: Begin //Estado atual: 1; Verifica caracter #3
If Str[I] in [#3] then begin
Pos := I;
Tam := 1;
Estado := 2;
Inc(I);
end else begin

{
http://www.sourcex.x-br.com/prog/artigos/ascii.html
Todos os caracteres entre #1 e #31 são considerados caracteres de controle,
por isto estes normalmente não aparecem em mensagens e podem ser excluídos
sem risco à interpretação da mensagem.

Os caracteres de 32 à 127 e os ASCII extendidos são os caracteres de input normais.
}
//Excluindo outros caracteres de controle simples.
If Str[I] in [#1 .. #31] then begin
Pos := I;
Tam := 1;
Inc(I);

//Delete(Str, Pos, Tam);
New(UnitCor);
UnitCor^.Pos := Pos;
UnitCor^.Tam := Tam;
Pilha.Push(UnitCor);
end else begin
Inc(I);
end;
end;
end; //Fim do Estado 1

2: Begin //Estado atual: 2; Verifica caracter
If Str[I] in ['0'..'9'] then begin
Inc(Tam);
Estado := 3;
Inc(I);
end else begin
Estado := 1;
//Inc(I);

//Delete(Str, Pos, Tam);
New(UnitCor);
UnitCor^.Pos := Pos;
UnitCor^.Tam := Tam;
Pilha.Push(UnitCor);
end;
end; //Fim do Estado 2

3: Begin //Estado atual: 3; Verifica caracteres ou ","
If Str[I] in ['0'..'9'] then begin
Inc(Tam);
Estado := 4;
Inc(I);
end else begin
If Str[I] in [','] then begin
Inc(Tam);
Estado := 5;
Inc(I);
end else begin
Estado := 1;
//Inc(I);

//Delete(Str, Pos, Tam);
New(UnitCor);
UnitCor^.Pos := Pos;
UnitCor^.Tam := Tam;
Pilha.Push(UnitCor);
end;
end;
end; //Fim do Estado 3

4: Begin //Estado Atual: 4; Verifica caracter ","
If Str[I] in [','] then begin
Inc(Tam);
Estado := 5;
Inc(I);
end else begin
Estado := 1;
//Inc(I);

//Delete(Str, Pos, Tam);
New(UnitCor);
UnitCor^.Pos := Pos;
UnitCor^.Tam := Tam;
Pilha.Push(UnitCor);
end;
end; //Fim Estado 4

5: Begin //Estado Atual 5; Verifica caracter
If Str[I] in ['0'..'9'] then begin
Inc(Tam);
Estado := 6;
Inc(I);
end else begin
Estado := 1;
Dec(Tam); //Se não houver número depois da virgula,
//significa que é uma vírgula normal
//Inc(I);

//Delete(Str, Pos, Tam);
New(UnitCor);
UnitCor^.Pos := Pos;
UnitCor^.Tam := Tam;
Pilha.Push(UnitCor);
end;
end; //Fim do Estado 5

6: Begin //Estado Atual 6; Verifica caracter
If Str[I] in ['0'..'9'] then begin
Inc(Tam);
Estado := 1;
//Inc(I);

//Delete(Str, Pos, Tam);
New(UnitCor);
UnitCor^.Pos := Pos;
UnitCor^.Tam := Tam;
Pilha.Push(UnitCor);
end else begin
Estado := 1;
//Inc(I);

//Delete(Str, Pos, Tam);
New(UnitCor);
UnitCor^.Pos := Pos;
UnitCor^.Tam := Tam;
Pilha.Push(UnitCor);
end;
end; //Fim do Estado 6

end; //Fim do Case
end; //Fim do laço For
//Fim da execução do autômato e início da execução da limpeza da string

While Pilha.Count > 0 do begin // Aqui efetuamos a limpeza na string
UnitCor := Pilha.Pop;
Delete(Str, UnitCor^.Pos, UnitCor^.Tam);
Dispose(UnitCor);
end;

Pilha.Free;

Result := Str;
end;



Versão em Python

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-

'''
Esta função para retirada dos caracteres de cor se baseia em um autômato
construído para este propósito, utilizando-se dos conceitos da Máquina de
Turing.

A Expressão pode ser entendida como: <#3 [num [num] [,[num [num]]]>

Licenciado sob FAIL.
'''

def LimpaString(Texto, Caracter = ''):

Str = Texto[:]
Pos = -1
Tam = -1
Estado = 1
Tamanho = len(Str)
Pilha = []

I = 0

while (I <= Tamanho) or (Estado <> 1):

Char = Str[I:I+1]

if Estado == 1: #Estado atual: 1; Verifica caracter #3
if Char in ('\x03',):
Pos = I
Tam = 1
Estado = 2
I += 1
elif Char in [chr(x) for x in range(1, 32)]:
#Explicação: Todos os caracteres entre #1 e #31 são conside-
#rados caracteres de controle, por isto estes normalmente não
#aparecem em mensagens e podem ser excluídos sem risco à in-
#terpretação da mensagem.

#Os caracteres de 32 à 127 e os ASCII extendidos são os carac-
#teres de input normais.

Pos = I
Tam = 1
I += 1
Pilha.append({'Pos': Pos, 'Tam': Tam})

else:
I += 1

elif Estado == 2: #Estado atual: 2; Verifica primeiro caracter
if Char in [str(x) for x in range(0, 10)]:
Tam += 1
Estado = 3
I += 1
else:
Estado = 1
Pilha.append({'Pos': Pos, 'Tam': Tam})

elif Estado == 3: #Estado atual: 3; Verifica caracteres ou ","
if Char in [str(x) for x in range(0, 10)]:
Tam += 1
Estado = 4
I += 1
elif Char in [',']:
Tam += 1
Estado = 5
I += 1
else:
Estado = 1
Pilha.append({'Pos': Pos, 'Tam': Tam})

elif Estado == 4: #Estado Atual: 4; Verifica caracter ","
if Char in [',']:
Tam += 1
Estado = 5
I += 1
else:
Estado = 1
Pilha.append({'Pos': Pos, 'Tam': Tam})

elif Estado == 5: #Estado Atual 5; Verifica caracter
if Char in [str(x) for x in range(0, 10)]:
Tam += 1
Estado = 6
I += 1
else: #Se não houver número depois da virgula, significaque é uma vírgula normal
Estado = 1
Tam -= 1
Pilha.append({'Pos': Pos, 'Tam': Tam})

elif Estado == 6: #Estado Atual 6; Verifica caracter
if Char in [str(x) for x in range(0, 10)]:
Tam += 1
Estado = 1
Pilha.append({'Pos': Pos, 'Tam': Tam})
else:
Estado = 1
Pilha.append({'Pos': Pos, 'Tam': Tam})

while len(Pilha) > 0:
Cor = Pilha.pop()
Str = Str[:Cor['Pos']] + Caracter + Str[Cor['Pos']+Cor['Tam']:]

return Str