Declension of words and initials in Delphi / Freepascal

Good New Year's Day everyone! In this article, I would like to tell you how I had to return to a legacy project in Pascal, and literally before saying goodbye to him, to lazarus, and to the absence of a dark theme out of the box .





Last time I explained that I am not a programmer by profession, but I use my favorite hobby to automate everything that comes to hand in the work of a lawyer. I am sure that 90% of all legal red tape can be successfully automated: maintaining a variety of databases and cards, drawing up documents according to templates, controlling the timing of tasks, using any auxiliary services that already have their own api to screw automation at a specific workplace, etc. etc. It is necessary to strive for this in order, according to the behests of Isaac Asimov, to free up the time of a lawyer for the implementation of the main task - to reflect on the terms of the contract and breed demagoguery in court.






So, many years ago I did a very large project to make my office work easier. He collected all the data on trademarks and patents (and there are several hundred of them), controlled the timing of payment of patent fees, formed payment orders, contracts, applications, and, of course, issued various reports. Actually, why in the past tense? The project is quite working. It was just developed according to all possible anti-patterns, with all the bicycles and crutches that were only found on Earth. To return to this Rolton (or doshirak) code in order to refactor it, oh, I didn't want to, because the meme " Let's rewrite everything in ... " is perfect here .





But, unfortunately, rewriting everything anew in a new language for a new platform or even several is a long and protracted business, and documents need to be stamped here and now. Therefore, I have to return to Pascal from time to time.





One of the beautiful days, the whole project was rebuilt on a 64-bit platform, and, to my surprise, the most favorite part fell: the generation of contracts and statements with full automation of all grammar and morphology - the declension of initials, positions and other words in the necessary cases, and See also singular / plural. The thing is that the old Delphic and proprietary padegUC library has ceased to be free in its 64-bit version.





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);
      
      



For everyone interested, I will keep my resulting library with a test window application for win in an open repository . Most likely, I will not begin anything in it, because now I have plunged into the open sea of ​​mobile development (kotlin) and python to implement the very same "rewrite everything in ..."





Happy New Year 2020 + '1' everyone!








All Articles