Recentemente tive a necessidade de implementar um corretor ortográfico em uma solução Delphi.
Pedi algumas indicações e me sugeriram:
http://www.devmedia.com.br/corretor-ortografico-no-delphi/2544
http://devexpress.com/Products/VCL/ExSpellChecker/
Não cheguei a testá-los mas foram muito bem recomendados.
Mas durante minhas pesquisas acabei me deparando com uma solução do Google.
Eu não tenho certeza, e se algum leitor for mais bem informado e puder fazer a gentileza de colocar as suas considerações nos comentários, mas o Google tem um recurso chamado Google Tool Bar Proxy e um dos recursos oferecidos é justamente o de correção ortográfica.
A URL do serviço é:
http://www.google.com/tbproxy/spell?lang=pt&hl=pt
Basicamente deve-se fazer um POST (HTTP) com um conteúdo XML e analisar o retorno.
Vamos imaginar então a palavra "coracao". O XML de requisição seria:
coracao
E uma resposta válida seria algo como:
coração
Indo ao ponto, desenvolvi o código abaixo devidamente comentado. É um projeto do tipo console.
É um ótimo exemplo pois tem uma pitada de XML e Expressão Regular.
Confesso que levei algumas boas horas para desenvolver este exemplo.
Me atrapalhei com o TXMLDocument e o UTF-8. Graças a este post de Caio Oliveira consegui resolver e me dei conta de um aparente bug. Achei estranho, mas de fato foi a solução.
Neste projeto foi desenvolvido a classe TCorretor onde efetivamente esta a solução.
program CorretorOrtografico; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, Xml.XMLDoc, Xml.XMLIntf, IdHTTP, System.Classes, WinApi.ActiveX, System.RegularExpressions, IdGlobal; type ////// Implementa o recurso de correção ortográfica oferecido pelo Google /// ////// Descende de TComponent para servir de base para o XMLDocument /// ////// José Mário Silva Guedes - jmarioguedes@gmail.com - eugostododelphi.blogspot.com /// TCorretor = class(TComponent) private ////// Estrutura do documento XML /// FXML: TXMLDocument; ////// Comunicação HTTP /// FHTTP: TidHTTP; public procedure AfterConstruction; override; ////// Processa efetivamente o corretor ortográfico /// /// /// Texto de entrada /// /// /// Possibilidades de correção /// /// /// Motivo de um eventual insucesso /// ////// Indica o sucesso da operação /// function Processar(AEntrada: string; ASaida: TStrings; AMotivo: string): Boolean; end; var bRet : Boolean; oCorretor: TCorretor; sEntrada : string; slSaida : TStringList; sMotivo : string; sPalavra : string; cSaida : Char; { TCorretor } procedure TCorretor.AfterConstruction; begin inherited; Self.FHTTP := TidHTTP.Create(Self); Self.FXML := TXMLDocument.Create(TDataModule.Create(Self)); end; function TCorretor.Processar(AEntrada: string; ASaida: TStrings; AMotivo: string): Boolean; const C_URL = 'http://www.google.com/tbproxy/spell?lang=pt&hl=pt'; var oRequest : TStringStream; oResponse : TStringStream; sResponse : string; sRequest : string; sResultado: string; _raiz : IXMLNode; _texto : IXMLNode; _resultado: IXMLNode; aPartes : TArray; begin oRequest := nil; oResponse := nil; try {$REGION 'Preparando o pedido'} Self.FXML.Active := False; Self.FXML.Active := True; Self.FXML.Version := '1.0'; Self.FXML.Encoding := 'UTF-16'; _raiz := Self.FXML.AddChild('spellrequest'); _raiz.Attributes['textalreadyclipped'] := '0'; _raiz.Attributes['ignoredups'] := '0'; _raiz.Attributes['ignoredigits'] := '1'; _raiz.Attributes['ignoreallcaps'] := '0'; _texto := Self.FXML.CreateNode('text'); _texto.Text := AEntrada; _raiz.ChildNodes.Add(_texto); {$ENDREGION} {$REGION 'Gambiarra do UTF-8'} Self.FXML.SaveToXML(sRequest); // http://www.caiooliveira.com.br/?p=422 // http://qc.embarcadero.com/wc/qcmain.aspx?d=37433 sRequest := TRegEx.Replace(sRequest, 'UTF-16', 'UTF-8'); oRequest := TStringStream.Create; oRequest.WriteString(sRequest); oRequest.Seek(0, 0); {$ENDREGION} {$REGION 'Request\Response'} Self.FHTTP.Request.Accept := 'text/xml'; Self.FHTTP.Request.ContentType := 'text/xml'; Self.FHTTP.Request.ContentEncoding := 'utf-8'; oResponse := TStringStream.Create; Self.FHTTP.Post(C_URL, oRequest, oResponse); sResponse := UTF8ToString(RawByteString(oResponse.DataString)); Self.FXML.Active := False; Self.FXML.LoadFromXML(sResponse); {$ENDREGION} {$REGION 'Analisando a resposta'} _resultado := Self.FXML.DocumentElement.ChildNodes.FindNode('c'); while (Assigned(_resultado)) do begin sResultado := _resultado.Text; aPartes := TRegEx.Split(sResultado, #9); for sResultado in aPartes do begin ASaida.Add(sResultado); end; _resultado := _resultado.NextSibling; end; Result := True; {$ENDREGION} finally if (Assigned(oRequest)) then begin oRequest.Free; end; if (Assigned(oResponse)) then begin oResponse.Free; end; end; end; begin oCorretor := nil; slSaida := nil; ReportMemoryLeaksOnShutdown := True; CoInitialize(nil); try Writeln('/--------------------------------------------------------------\'); Writeln('| .:: DEMONSTRAÇÃO DE USO DO CORRETOR ORTOGRÁFICO GOOGLE ::. |'); Writeln('| jmarioguedes@gmail.com - http://eugostododelphi.blogspot.com |'); Writeln('\--------------------------------------------------------------/'); Writeln(''); Writeln(''); oCorretor := TCorretor.Create(nil); slSaida := TStringList.Create; repeat write('Digite um texto: '); Readln(sEntrada); Writeln(''); slSaida.Clear; bRet := oCorretor.Processar(sEntrada, slSaida, sMotivo); if (bRet) then begin if (slSaida.Count > 0) then begin for sPalavra in slSaida do begin Writeln('-> ' + sPalavra); end; Writeln(''); end else begin Writeln('Não houve resultados'); end; end else begin Writeln(Format('Insucesso na correção: ', [sMotivo])); end; Write('Tecle X para cancelar ou qualquer outra tecla para continuar: '); ReadLn(cSaida); until (CharInSet(cSaida, ['X', 'x'])); finally if (Assigned(oCorretor)) then begin oCorretor.Free; end; if (Assigned(slSaida)) then begin slSaida.Free; end; Writeln('- Fim do Sistema - '); Readln; end; end.