Declinação de palavras e iniciais em Delphi / Freepascal

Bom dia de ano novo a todos! Neste artigo, gostaria de contar como tive que voltar a um projeto de legado em Pascal, e literalmente antes de dizer adeus a ele, a Lazarus e à ausência de um tema escuro fora da caixa .





Da última vez, expliquei que não sou programador de profissão, mas uso meu hobby favorito para automatizar tudo o que vem ao caso no trabalho de um advogado. Tenho certeza de que 90% de toda a burocracia legal pode ser automatizada com sucesso: manter uma variedade de bancos de dados e cartões, redigir documentos de acordo com modelos, controlar o tempo de tarefas, usar quaisquer serviços auxiliares que já tenham sua própria API para aparafusar a automação em um local de trabalho específico, etc. etc. É preciso lutar por isso para, segundo as ordens de Isaac Asimov, liberar o tempo de um advogado para a execução da tarefa principal - refletir sobre os termos do contrato e gerar demagogia no tribunal.






Então, muitos anos atrás, fiz um projeto muito grande para facilitar o meu trabalho de escritório. Ele coletou todos os dados sobre marcas e patentes (e existem várias centenas delas), controlou o tempo de pagamento das taxas de patentes, formou ordens de pagamento, contratos, aplicações e, é claro, emitiu vários relatórios. Na verdade, por que no pretérito? O projeto está funcionando bastante. Ele acabou de ser desenvolvido de acordo com todos os anti-padrões possíveis, com todas as bicicletas e muletas que só eram encontradas na Terra. Para voltar a este Rolton (ou doshirak) código , a fim de refazer-lo, oh, eu não queria, porque o meme " Vamos reescrever tudo em ... " é perfeito aqui .





Mas, infelizmente, reescrever tudo de novo em um novo idioma para uma nova plataforma ou mesmo várias é uma tarefa longa e demorada, e os documentos precisam ser carimbados aqui e agora. Portanto, tenho que voltar a Pascal de vez em quando.





Um dos dias lindos, todo o projeto foi reconstruído em uma plataforma de 64 bits e, para minha surpresa, a parte mais favorita caiu: a geração de contratos e extratos com total automação de toda a gramática e morfologia - o declínio de iniciais, posições e outras palavras nos casos necessários, e Veja também singular / plural. O fato é que a antiga biblioteca Delphic e proprietária padegUC deixou de ser gratuita em sua versão de 64 bits.





32- , . .





- , . , :





IInitialsMorpher = interface
  function GetInitials(Initials: string): CasesResponse;
  function GetWordsCase(Words: string): CasesResponse;
  function GetGenderAndInitials(Initials: string; var Gender: TGender): CasesResponse;
end;
      
      



, , -: (.. ), , , , , , .. CasesResponse , Gender - :





TWordCase = (Nominative, Gentitive, Dative, Accusative, Instrumental, Prepositional);
TGender = (Male, Female, UnrecognizedGender);
CasesResponse = array[TWordCase] of string;
      
      



. , :

















DaData





-





-





-





- -





-





Pymorphy





github





- MIT , python





- Corpora ( )





- , .. , , , ..





- , , ..





Morphos





- MIT , php





-





-





- ,





, Morphos, / .





rest api, json, , http, :





generic function JSONfromRestUri<T>(Uri: string): T;
var
  HTTPSender: THTTPSend;
  JSONStreamer: TJSONDeStreamer;
  Json: TJSONObject;
begin
  HTTPSender := THTTPSend.Create;
  JSONStreamer := TJSONDeStreamer.Create(nil);
  HTTPSender.Clear;
  Result := T.Create;
  if not HTTPSender.HTTPMethod('GET', Uri) then 
  		raise EInOutError.Create(RESTOUT_ERROR);
  JSON := GetJSON(HTTPSender.Document) as TJSONObject;
  JSONStreamer.JSONToObject(JSON, Result);
  FreeAndNil(JSON);
  FreeAndNil(JSONStreamer);
  FreeAndNil(HTTPSender);
end;
      
      



Freepascal Synapse Fpjson, (httpsend, fpjson, fpjsonrtti) uses. json rtti, .. , -, published, -, (, , ), -, json. , @SerializedName , .





Morphos :





MORPHOS_URL = 'http://morphos.io/api/inflect-name?name=%s&_format=json';
      
      



json , - / , , name gender:





{
    "name": " ",
    "cases": [
        " ",
        " ",
        " ",
        " ",
        " ",
        "  "
    ],
    "gender": "m"
}
      
      



IInitialsMorpher Morpher. , json Fpjson ( , TPersistent):





TMorphosResponse = class(TPersistent)
  private
    fCases: TStrings;
    fGender: string;
    fName: string;
  public
    constructor Create;
    destructor Destroy; override;
  published
    property name: string read fName write fName;
    property cases: TStrings read fCases write fCases;
    property gender: string read fGender write fGender;
  end;
      
      



:





TMorphosImpl = class(TInterfacedObject, IInitialsMorpher)
  public
    function GetInitials (Initials: string): CasesResponse;
    function GetWordsCase (Words: string): CasesResponse;
    function GetGenderAndInitials(Initials: string; var Gender: TGender): CasesResponse;
  end;
      
      



, :





function TMorphosImpl.GetGenderAndInitials(Initials: string; var Gender: TGender): CasesResponse;
var
  inf: TWordCase;
  i: integer = 0;
  response: TMorphosResponse;
begin
  response := specialize JSONfromRestUri<TMorphosResponse>
                (Replacetext(Format(MORPHOS_URL, [Initials]), ' ', '+'));
  for inf in TWordCase do begin
      Result[inf] := response.cases[i];
      inc(i);
  end;
  case response.gender of
       'm': Gender := Male;
       'f': Gender := Female;
       else Gender := UnrecognizedGender;
  end;
  FreeAndNil(response);
end;
      
      



, . , ( ) , , - :





function TMorphosImpl.GetInitials(Initials: string): CasesResponse;
var
  MokeGender: TGender = UnrecognizedGender;
begin
  Result := GetGenderAndInitials(Initials, MokeGender);
end;

function TMorphosImpl.GetWordsCase(Words: string): CasesResponse;
var
  inf: TWordCase;
begin
  Result := GetInitials(Words);
  for inf in TWordCase do
    Result[inf] := UTF8LowerString(Result[inf]);
end;
      
      



, . , . . , , , DI- - "" .





- -, ( , , - ?) - http-. Morphos , DaData , 10 .





, . , json ashMap- Generics.Collections - , freepascal delphi. , - ( , http- , ).





Morphos :





Morpher := TMorphFabric.Create(MORPHOS);
//...
response := Morpher.GetInitials(Text)
StringList.AddStrings(response);
      
      



Para todos os interessados, vou manter minha biblioteca resultante com um aplicativo de janela de teste para vencer em um repositório aberto . Provavelmente, não começarei nada nele, porque agora mergulhei no mar aberto do desenvolvimento móvel (kotlin) e python para implementar o mesmo "reescrever tudo em ..."





Feliz Ano Novo 2020 + '1' para todos!








All Articles