Die Geschichte eines kleinen Projekts über zwölf Jahre (über BIRMA.NET zum ersten Mal und ehrlich gesagt aus erster Hand)

Die Geburt dieses Projekts kann als eine kleine Idee angesehen werden, die mir irgendwann Ende 2007 kam und die ihre endgültige Form erst 12 Jahre später finden sollte (zu diesem Zeitpunkt – natürlich, obwohl die aktuelle Umsetzung laut … ist für den Autor sehr zufriedenstellend).

Angefangen hat alles damit, dass ich im Zuge der Ausübung meiner damaligen Amtspflichten in der Bibliothek darauf aufmerksam machte, dass der Prozess der Eingabe von Daten aus dem gescannten Text von Inhaltsverzeichnissen von Buch- (und Musik-)Publikationen in die bestehende Datenbank, Offenbar lässt sich dies erheblich vereinfachen und automatisieren, indem man sich die Eigenschaft der Ordnung und Wiederholbarkeit aller für die Eingabe erforderlichen Daten zunutze macht, wie z. B. den Namen des Autors des Artikels (wenn es sich um eine Sammlung von Artikeln handelt), den Titel von der Artikel (oder der im Inhaltsverzeichnis wiedergegebene Untertitel) und die Seitenzahl des aktuellen Inhaltsverzeichniselements. Zunächst war ich praktisch davon überzeugt, dass sich im Internet leicht ein für diese Aufgabe geeignetes System finden ließe. Als ich überrascht war, dass ich ein solches Projekt nicht finden konnte, beschloss ich, es selbst umzusetzen.

Nach relativ kurzer Zeit begann der erste Prototyp zu funktionieren, den ich sofort in meinen täglichen Aktivitäten nutzte und ihn gleichzeitig an allen Beispielen, die mir zur Verfügung standen, debuggte. Glücklicherweise kam ich an meinem gewohnten Arbeitsplatz, an dem ich keineswegs Programmierer war, dann trotzdem mit sichtbaren „Ausfällen“ in meiner Arbeit davon, während derer ich intensiv an der Fehlersuche meiner Idee war – eine fast undenkbare Sache in der aktuellen Realität, die das impliziert tägliche Berichte über die während des Tages geleistete Arbeit. Insgesamt dauerte die Ausarbeitung des Programms nicht weniger als etwa ein Jahr, aber auch danach konnte man das Ergebnis kaum als vollendet gelungen bezeichnen – zu viele unterschiedliche Konzepte waren zunächst festgelegt, die für die Umsetzung nicht ganz klar waren: optionale Elemente, die es können übersprungen werden; Vorwärtsansicht von Elementen (um vorherige Elemente in Suchergebnissen zu ersetzen); sogar unser eigener Versuch, so etwas wie reguläre Ausdrücke zu implementieren (die eine einzigartige Syntax haben). Ich muss sagen, dass ich zuvor das Programmieren etwas aufgegeben hatte (für etwa 8 Jahre, wenn nicht länger), sodass die neue Gelegenheit, meine Fähigkeiten auf eine interessante und notwendige Aufgabe anzuwenden, meine Aufmerksamkeit völlig gefesselt hat. Es ist nicht verwunderlich, dass der resultierende Quellcode – mangels klarer Ansätze für sein Design meinerseits – ziemlich schnell zu einer unvorstellbaren Mischung aus unterschiedlichen Teilen in der C-Sprache mit einigen Elementen von C++ und Aspekten der visuellen Programmierung (ursprünglich war es …) wurde Es wurde beschlossen, ein Designsystem wie Borland C++ Builder zu verwenden – „fast Delphi, aber in C“). All dies trug jedoch letztendlich dazu bei, die täglichen Aktivitäten unserer Bibliothek zu automatisieren.

Gleichzeitig beschloss ich, für alle Fälle Kurse zur Ausbildung professioneller Softwareentwickler zu belegen. Ich weiß nicht, ob es dort tatsächlich möglich ist, „Programmierer zu werden“ von der Pike auf zu erlernen, aber unter Berücksichtigung der Fähigkeiten, die ich damals bereits hatte, war ich in der Lage, Technologien einigermaßen zu beherrschen, die zu dieser Zeit relevanter waren, wie z wie C#, Visual Studio für die Entwicklung unter .NET sowie einige Technologien im Zusammenhang mit Java, HTML und SQL. Die gesamte Ausbildung dauerte insgesamt zwei Jahre und diente als Ausgangspunkt für ein weiteres Projekt von mir, das sich letztendlich über mehrere Jahre erstreckte – dies ist jedoch ein Thema für eine separate Veröffentlichung. An dieser Stelle wäre nur anzumerken, dass ich versucht habe, die bereits vorhandenen Entwicklungen des beschriebenen Projekts zu adaptieren, um eine vollwertige Fensteranwendung in C# und WinForms zu erstellen, die die erforderliche Funktionalität implementiert, und diese als Grundlage für das zu verwenden bevorstehende Diplomarbeit.
Im Laufe der Zeit erschien mir diese Idee würdig, auf jährlichen Konferenzen unter Beteiligung von Vertretern verschiedener Bibliotheken wie „LIBKOM“ und „CRIMEA“ geäußert zu werden. Die Idee ja, aber nicht meine damalige Umsetzung. Dann habe ich auch gehofft, dass jemand es mit kompetenteren Ansätzen umschreiben würde. Auf die eine oder andere Weise beschloss ich, bis 2013 einen Bericht über meine Vorarbeit zu schreiben und ihn zusammen mit einem Antrag auf ein Stipendium für die Teilnahme an der Konferenz an das Organisationskomitee der Konferenz zu senden. Zu meiner Überraschung wurde mein Antrag genehmigt und ich begann, einige Verbesserungen am Projekt vorzunehmen, um es für die Präsentation auf der Konferenz vorzubereiten.

Zu diesem Zeitpunkt hatte das Projekt bereits den neuen Namen BIRMA erhalten und verschiedene zusätzliche (nicht so sehr vollständig implementierte, sondern eher angenommene) Fähigkeiten erworben – Alle Details finden Sie in meinem Bericht.

Ehrlich gesagt war es schwierig, BIRMA 2013 als etwas Vollständiges zu bezeichnen; Ehrlich gesagt war es ein sehr heikles, in Eile gemachtes Handwerk. In Bezug auf den Code gab es praktisch überhaupt keine besonderen Neuerungen, außer einem eher hilflosen Versuch, eine Art einheitliche Syntax für den Parser zu erstellen, die im Aussehen an die Formatierungssprache IRBIS 64 (und tatsächlich auch an das ISIS-System) erinnert. mit Klammern als zyklische Strukturen; warum Ich fand es damals ziemlich cool). Der Parser ist hoffnungslos auf diese Klammerkreise des entsprechenden Typs gestoßen (da Klammern auch eine andere Rolle spielten, nämlich beim Parsen optionale Strukturen zu markieren, die übersprungen werden können). Ich verweise nochmals alle, die sich mit der damals schwer vorstellbaren, ungerechtfertigten Syntax von BIRMA näher vertraut machen wollen, auf meinen damaligen Bericht.

Abgesehen von den Schwierigkeiten mit meinem eigenen Parser habe ich im Allgemeinen nichts mehr zum Code dieser Version zu sagen – außer der umgekehrten Konvertierung der vorhandenen Quellen in C++ unter Beibehaltung einiger typischer Merkmale des .NET-Codes (um ehrlich zu sein). schwer zu verstehen, was genau mich dazu bewogen hat, alles zurückzustellen - wahrscheinlich eine dumme Angst davor, meine Quellcodes geheim zu halten, als ob es sich um etwas Äquivalentes zum Geheimrezept von Coca-Cola handeln würde).

Vielleicht ist diese dumme Entscheidung auch der Grund für die Schwierigkeiten, die resultierende DLL-Bibliothek mit der vorhandenen Schnittstelle einer selbstgebauten Workstation zur Eingabe von Daten in einen elektronischen Katalog zu koppeln (ja, eine weitere wichtige Tatsache habe ich nicht erwähnt: Von nun an alle Der Code der BIRMA-„Engine“ war wie erwartet, er wird vom Schnittstellenteil getrennt und in die entsprechende DLL gepackt. Warum es für diese Zwecke notwendig war, eine separate Workstation zu schreiben, die in ihrem Erscheinungsbild und der Art der Interaktion mit dem Benutzer ohnehin schamlos dieselbe Workstation „Catalogizer“ des IRBIS 64-Systems kopierte, ist eine andere Frage. Kurz gesagt: Es gab meinen damaligen Entwicklungen für meine Abschlussarbeit die nötige Solidität (ansonsten reichte die unverdauliche Parser-Engine allein irgendwie nicht aus). Außerdem stieß ich dann auf einige Schwierigkeiten, die Schnittstelle der Cataloger-Workstation mit meinen eigenen Modulen zu implementieren, die sowohl in C++ als auch in C# implementiert waren, und direkt auf meine Engine zuzugreifen.

Im Allgemeinen war es seltsamerweise dieser eher ungeschickte Prototyp des zukünftigen BIRMA.NET, der für die nächsten vier Jahre mein „Arbeitstier“ werden sollte. Man kann nicht sagen, dass ich in dieser Zeit nicht zumindest versucht habe, Wege für eine neue, vollständigere Umsetzung einer langjährigen Idee zu finden. Neben anderen Neuerungen hätte es bereits verschachtelte zyklische Sequenzen geben sollen, die optionale Elemente hätten enthalten können – so wollte ich die Idee universeller Vorlagen für bibliografische Beschreibungen von Publikationen und verschiedenen anderen interessanten Dingen zum Leben erwecken. In meiner damaligen praktischen Tätigkeit war dies alles jedoch wenig gefragt und für die Eingabe von Inhaltsverzeichnissen reichte die damalige Umsetzung völlig aus. Darüber hinaus begann die Entwicklungsrichtung unserer Bibliothek immer mehr in Richtung der Digitalisierung von Museumsarchiven, der Berichterstattung und anderen für mich wenig interessanten Aktivitäten abzuweichen, was mich letztendlich dazu zwang, sie endgültig zu verlassen und denen Platz zu machen, die es wollten Seien Sie mit all dem zufriedener.

Paradoxerweise schien das BIRMA-Projekt, das zu diesem Zeitpunkt bereits alle charakteristischen Merkmale eines typischen langfristigen Bauprojekts aufwies, nach diesen dramatischen Ereignissen sein lang erwartetes neues Leben zu beginnen! Ich hatte mehr Freizeit für müßige Gedanken, ich fing wieder an, das World Wide Web auf der Suche nach etwas Ähnlichem zu durchsuchen (zum Glück konnte ich jetzt schon erraten, dass ich das alles nicht irgendwo, sondern auf GitHub suchen sollte) und irgendwo in der Anfang dieses Jahres bin ich schließlich unter dem unbedeutenden Namen auf ein entsprechendes Produkt des bekannten Unternehmens Salesforce gestoßen Gorp. An sich konnte es fast alles tun, was ich von einer solchen Parser-Engine brauchte – nämlich einzelne Fragmente intelligent aus beliebigem, aber klar strukturiertem Text zu isolieren und gleichzeitig eine ziemlich benutzerfreundliche Oberfläche für den Endbenutzer zu haben, einschließlich so verständlicher Essenzen wie ein Muster, eine Vorlage und ein Vorkommen und nutzt gleichzeitig die bekannte Syntax regulärer Ausdrücke, die durch die Unterteilung in bestimmte semantische Gruppen zum Parsen ungleich lesbarer wird.

Im Allgemeinen habe ich beschlossen, dass dies das Richtige ist Gorp (Ich frage mich, was dieser Name bedeutet? Vielleicht eine Art „allgemein orientierter regulärer Parser“?) – genau das, wonach ich schon lange gesucht habe. Allerdings war die unmittelbare Umsetzung für meine eigenen Bedürfnisse so problematisch, dass diese Engine eine zu strikte Einhaltung der strukturellen Reihenfolge des Quelltextes erforderte. Für einige Berichte wie Protokolldateien (sie wurden nämlich von den Entwicklern als klare Beispiele für die Verwendung des Projekts platziert) ist dies durchaus geeignet, für dieselben Texte gescannter Inhaltsverzeichnisse ist dies jedoch unwahrscheinlich. Schließlich kann dieselbe Seite mit einem Inhaltsverzeichnis mit den Wörtern „Inhaltsverzeichnis“, „Inhalt“ und anderen vorläufigen Beschreibungen beginnen, die wir nicht in den Ergebnissen der beabsichtigten Analyse platzieren (und manuell abschneiden) müssen jedes Mal ist auch unbequem). Darüber hinaus kann die Seite zwischen einzelnen sich wiederholenden Elementen, wie dem Namen des Autors, dem Titel und der Seitenzahl, eine gewisse Menge Müll enthalten (z. B. Zeichnungen und nur zufällige Zeichen), was ebenfalls schön wäre Abschneiden. Allerdings war der letzte Aspekt noch nicht so bedeutsam, aber aufgrund des ersten konnte die bestehende Implementierung nicht von einer bestimmten Stelle aus mit der Suche nach den notwendigen Strukturen im Text beginnen, sondern sie einfach von Anfang an verarbeiten und nicht finden Ich habe dort Muster vorgegeben und... meinen Job beendet. Offensichtlich waren einige Anpassungen erforderlich, um zumindest etwas Platz zwischen den sich wiederholenden Strukturen zu schaffen, und das brachte mich wieder an die Arbeit.

Ein weiteres Problem bestand darin, dass das Projekt selbst in Java implementiert wurde, und wenn ich in Zukunft vorhabe, diese Technologie mit bekannten Anwendungen zur Eingabe von Daten in bestehende Datenbanken (wie „Cataloger“ von Irbis) zu verbinden, dann zumindest Tun Sie dies in C# und .NET. Es ist nicht so, dass Java selbst eine schlechte Sprache wäre – ich habe sie sogar einmal verwendet, um eine interessante Fensteranwendung zu implementieren, die die Funktionalität eines heimischen programmierbaren Taschenrechners implementierte (im Rahmen eines Kursprojekts). Und in Bezug auf die Syntax ist es dem gleichen Cis sehr ähnlich. Nun, das ist nur ein Pluspunkt: Je einfacher es für mich ist, ein bestehendes Projekt abzuschließen. Allerdings wollte ich nicht noch einmal in diese eher ungewöhnliche Welt der Fenster- (oder besser Desktop-) Java-Technologien eintauchen – schließlich war die Sprache selbst nicht für eine solche Verwendung „zugeschnitten“ und ich sehnte mich überhaupt nicht nach einer Wiederholung die bisherige Erfahrung. Vielleicht liegt es gerade daran, dass C# in Verbindung mit WinForms viel näher an Delphi ist, mit dem viele von uns einst angefangen haben. Glücklicherweise wurde recht schnell die nötige Lösung gefunden – in Form des Projekts IKVM.NET, wodurch es einfach ist, vorhandene Java-Programme in verwalteten .NET-Code zu übersetzen. Das Projekt selbst war zwar zu diesem Zeitpunkt von den Autoren bereits aufgegeben worden, aber seine jüngste Umsetzung ermöglichte es mir, die notwendigen Maßnahmen für die Quelltexte recht erfolgreich durchzuführen Gorp.

Also habe ich alle notwendigen Änderungen vorgenommen und alles in eine DLL des entsprechenden Typs zusammengestellt, die problemlos von allen in Visual Studio erstellten Projekten für .NET Framework „aufgegriffen“ werden konnte. In der Zwischenzeit habe ich eine weitere Ebene erstellt, um die zurückgegebenen Ergebnisse bequem darzustellen Gorp, in Form entsprechender Datenstrukturen, die bequem in einer Tabellenansicht verarbeitet werden könnten (wobei sowohl Zeilen als auch Spalten als Grundlage verwendet werden; sowohl Wörterbuchschlüssel als auch numerische Indizes). Nun, die notwendigen Dienstprogramme selbst zur Verarbeitung und Anzeige der Ergebnisse wurden recht schnell geschrieben.

Auch der Prozess der Anpassung von Vorlagen für die neue Engine, um ihr beizubringen, vorhandene Muster gescannter Texte von Inhaltsverzeichnissen zu analysieren, verursachte keine besonderen Komplikationen. Tatsächlich musste ich überhaupt nicht auf meine vorherigen Vorlagen zurückgreifen: Ich habe einfach alle notwendigen Vorlagen von Grund auf neu erstellt. Während die Vorlagen, die für die Zusammenarbeit mit der vorherigen Version des Systems entwickelt wurden, einen relativ engen Rahmen für Texte vorgaben, die mit ihrer Hilfe korrekt analysiert werden konnten, ermöglichte die neue Engine bereits die Entwicklung ziemlich universeller Vorlagen, die für verschiedene Arten von Markups geeignet sind einmal. Ich habe sogar versucht, eine Art umfassende Vorlage für jeden beliebigen Inhaltsverzeichnistext zu schreiben, allerdings natürlich trotz all der neuen Möglichkeiten, die sich für mich eröffnen, darunter insbesondere die begrenzte Möglichkeit, dieselben verschachtelten Wiederholungssequenzen zu implementieren ( (z. B. Nachnamen und Initialen mehrerer Autoren hintereinander) erwies sich dies als Utopie.

Vielleicht wird es in Zukunft möglich sein, ein bestimmtes Konzept von Meta-Vorlagen umzusetzen, das den Quelltext gleichzeitig auf Übereinstimmung mit mehreren der verfügbaren Vorlagen überprüfen und dann entsprechend den erhaltenen Ergebnissen auswählen kann die am besten geeignete Methode mithilfe eines intelligenten Algorithmus. Aber jetzt beschäftigte mich eine andere Frage mehr. Ein Parser wie GorpTrotz all seiner Vielseitigkeit und der von mir vorgenommenen Modifikationen war es von Natur aus immer noch nicht in der Lage, eine scheinbar einfache Sache zu tun, die mein selbst geschriebener Parser von der ersten Version an konnte. Nämlich: Er hatte die Fähigkeit, alle Fragmente, die mit der in der an der richtigen Stelle verwendeten Vorlage angegebenen Maske übereinstimmen, aus dem Quelltext zu finden und zu extrahieren, ohne sich überhaupt dafür zu interessieren, was der gegebene Text in den Zwischenräumen zwischen diesen Fragmenten enthält. Bisher habe ich die neue Engine nur geringfügig verbessert, sodass sie ab der aktuellen Position nach allen möglichen neuen Wiederholungen einer bestimmten Sequenz solcher Masken suchen kann, sodass die Möglichkeit besteht, dass im Text Sätze beliebiger Zeichen vorhanden sind, die vollständig vorhanden sind beim Parsen unberücksichtigt, eingeschlossen zwischen den erkannten sich wiederholenden Strukturen. Allerdings war es dadurch nicht möglich, die nächste Maske unabhängig von den Ergebnissen der Suche nach dem vorherigen Fragment mit der entsprechenden Maske festzulegen: Die Strenge der beschriebenen Textstruktur ließ immer noch keinen Raum für willkürliche Einfügungen unregelmäßiger Zeichen.

Und wenn dieses Problem bei den Beispielen von Inhaltsverzeichnissen, auf die ich gestoßen bin, noch nicht so schwerwiegend schien, dann ist es bei dem Versuch, einen neuen Parsing-Mechanismus auf eine ähnliche Aufgabe des Parsens des Inhalts einer Website anzuwenden (d. h. das gleiche Parsen), der Fall Einschränkungen sind hier, sie traten mit all ihrer Offensichtlichkeit in Erscheinung. Schließlich ist es ganz einfach, die notwendigen Masken für Web-Markup-Fragmente festzulegen, zwischen denen sich die gesuchten Daten (die extrahiert werden müssen) befinden sollen, aber wie können wir den Parser zwingen, sofort mit dem nächsten fortzufahren? Ähnliches Fragment, trotz aller möglichen Tags und HTML-Attribute, die in den Zwischenräumen platziert werden können?

Nachdem ich ein wenig nachgedacht hatte, beschloss ich, ein paar Servicemuster einzuführen (%all_before) и (%all_after)Dies dient dem offensichtlichen Zweck, sicherzustellen, dass alles, was möglicherweise im Quelltext enthalten ist, vor allen darauf folgenden Mustern (Masken) übersprungen wird. Darüber hinaus, wenn (%all_before) Ich habe also all diese willkürlichen Einschlüsse einfach ignoriert (%all_after)Im Gegenteil, sie konnten dem gewünschten Fragment hinzugefügt werden, nachdem sie vom vorherigen Fragment verschoben wurden. Es klingt ganz einfach, aber um dieses Konzept umzusetzen, musste ich die Gorp-Quellen noch einmal durchforsten, um die notwendigen Änderungen vorzunehmen, um die bereits implementierte Logik nicht zu zerstören. Am Ende haben wir es geschafft (obwohl sogar die allererste, wenn auch sehr fehlerhafte Implementierung meines Parsers geschrieben wurde, und zwar noch schneller – in ein paar Wochen). Von nun an nahm das System eine wirklich universelle Form an – nicht weniger als 12 Jahre nach den ersten Versuchen, es zum Funktionieren zu bringen.

Natürlich ist dies nicht das Ende unserer Träume. Sie können den Gorp-Vorlagenparser auch vollständig in C# umschreiben und dabei eine der verfügbaren Bibliotheken zur Implementierung einer kostenlosen Grammatik verwenden. Ich denke, der Code sollte deutlich vereinfacht werden, und das wird es uns ermöglichen, das Erbe in Form vorhandener Java-Quellen loszuwerden. Aber mit dem vorhandenen Engine-Typ ist es auch durchaus möglich, verschiedene interessante Dinge zu tun, einschließlich des Versuchs, die bereits erwähnten Meta-Vorlagen zu implementieren, ganz zu schweigen vom Parsen verschiedener Daten von verschiedenen Websites (was ich jedoch nicht ausschließe). dass dafür bestehende spezialisierte Softwaretools besser geeignet sind – ich habe nur noch nicht die entsprechenden Erfahrungen damit gemacht).

Übrigens habe ich diesen Sommer bereits eine Einladung per E-Mail von einem Unternehmen erhalten, das Salesforce-Technologien nutzt (dem Entwickler des Originals). Gorp), ein Vorstellungsgespräch für die anschließende Arbeit in Riga bestehen. Leider bin ich im Moment nicht bereit für solche Umschichtungen.

Wenn dieses Material Interesse weckt, werde ich im zweiten Teil versuchen, die Technologie zum Kompilieren und anschließenden Parsen von Vorlagen am Beispiel der in Salesforce verwendeten Implementierung näher zu beschreiben Gorp (Meine eigenen Ergänzungen, mit Ausnahme einiger bereits beschriebener Funktionswörter, bewirken praktisch keine Änderungen an der Vorlagensyntax selbst, also fast der gesamten Dokumentation für das Originalsystem Gorp Auch für meine Version geeignet).

Source: habr.com

Kommentar hinzufügen