Die Geburt dieses Projekts kann als eine kleine Idee angesehen werden, die mich Ende 2007 irgendwo besuchte und die erst 12 Jahre später ihre endgültige Form finden sollte (zu diesem Zeitpunkt - natürlich, obwohl die derzeitige Umsetzung nach Meinung des Autors sehr zufriedenstellend ist). .
Alles begann damit, dass ich bei der Erfüllung meiner offiziellen Aufgaben in der Bibliothek darauf aufmerksam gemacht habe, dass der Vorgang der Eingabe von Daten aus dem gescannten Text des Inhaltsverzeichnisses von Buch- (und Musik-) Veröffentlichungen in die vorhandene Datenbank offensichtlich erheblich vereinfacht werden kann und automatisieren unter Verwendung der Eigenschaft der Ordnungsmäßigkeit und Wiederholbarkeit aller für die Eingabe erforderlichen Daten, wie z. B. den Namen des Autors des Artikels (wenn es sich um eine Sammlung von Artikeln handelt), den Namen des Artikels (oder den im Inhaltsverzeichnis angegebenen Untertitel) und Die Seite des aktuellen Inhaltsverzeichnisses. Anfangs war ich fast davon überzeugt, dass ein für diese Aufgabe geeignetes System im Internet leicht zu finden ist. Als es mich überraschte, dass ich ein solches Projekt nicht finden konnte, beschloss ich, es selbst umzusetzen.
Nach relativ kurzer Zeit begann der erste Prototyp zu arbeiten, den ich sofort für meine täglichen Aktivitäten verwendete, und debuggte ihn gleichzeitig mit allen Beispielen, die mir zur Verfügung standen. Glücklicherweise konnte ich an meinem gewohnten Arbeitsplatz, an dem ich keineswegs Programmierer war, immer noch mit sichtbaren „Ausfallzeiten“ in der Arbeit davonkommen, in denen ich hart daran gearbeitet habe, meine Idee zu debuggen - eine fast undenkbare Sache in der heutigen Realität, die tägliche Berichte darüber impliziert die tagsüber geleistete Arbeit. Der Polierprozess des Programms dauerte insgesamt nicht weniger als ein Jahr, aber auch danach konnte das Ergebnis kaum als vollständig erfolgreich bezeichnet werden - es gab zu viele verschiedene Konzepte, die von Anfang an nicht ganz verständlich waren: optionale Elemente, die übersprungen werden konnten; führende Ansicht von Elementen (zum Ersetzen der Suchergebnisse vorheriger Elemente); sogar Ihr eigener Versuch, so etwas wie reguläre Ausdrücke zu implementieren (mit einer bestimmten Syntax). Ich muss sagen, dass ich es vorher geschafft habe, ein bisschen zu programmieren (für ungefähr 8 Jahre, wenn nicht mehr), so dass eine neue Gelegenheit, meine Fähigkeiten auf eine interessante und notwendige Aufgabe anzuwenden, meine Aufmerksamkeit auf sich gezogen hat. Es ist nicht verwunderlich, dass der resultierende Quellcode - da für mich keine verständlichen Ansätze zu seiner Gestaltung vorhanden waren - schnell zu einer unvorstellbaren Mischung unterschiedlicher Teile in der C-Sprache mit einigen C ++ - Elementen und Aspekten der visuellen Programmierung wurde (ursprünglich wurde beschlossen, ihn zu verwenden) ein solches Design-System wie Borland C ++ Builder - "fast Delphi, aber in C"). All dies hat sich jedoch letztendlich in der Automatisierung der täglichen Aktivitäten unserer Bibliothek ausgezahlt.
Gleichzeitig habe ich mich für alle Fälle entschlossen, Schulungen für professionelle Softwareentwickler zu absolvieren. Ich weiß nicht, ob es möglich ist, wirklich "von einem Programmierer" von Grund auf zu lernen, aber unter Berücksichtigung der Fähigkeiten, die ich zu diesem Zeitpunkt bereits hatte, konnte ich etwas fortgeschrittenere Technologien wie C #, Visual Studio für die Entwicklung unter beherrschen. NET sowie einige der Technologien in Bezug auf Java, HTML und SQL. Die gesamte Ausbildung dauerte insgesamt zwei Jahre und diente als Ausgangspunkt für ein weiteres meiner Projekte, das sich schließlich über mehrere Jahre erstreckte - dies ist jedoch bereits ein Thema für eine separate Veröffentlichung. An dieser Stelle sei nur darauf hingewiesen, dass ich versucht habe, die Erfahrungen, die ich bereits mit dem beschriebenen Projekt gesammelt habe, anzupassen, um eine vollständige Fensteranwendung in C # und WinForms zu erstellen, die die erforderlichen Funktionen implementiert, und sie als Grundlage für das bevorstehende Abschlussprojekt zu verwenden.
Im Laufe der Zeit schien diese Idee es wert zu sein, auf solchen jährlichen Konferenzen unter Beteiligung von Vertretern verschiedener Bibliotheken wie LIBCOM und CRIMEA geäußert zu werden. Die Idee ist ja, aber keineswegs meine Erkenntnis dieser Zeit. Dann hoffte ich unter anderem auch, dass jemand es mit kompetenteren Ansätzen umschreiben würde. Auf die eine oder andere Weise habe ich bis 2013 beschlossen, einen Bericht über meine Vorarbeiten zu erstellen und ihn mit einem Antrag auf Gewährung eines Zuschusses für die Teilnahme an der Konferenz an das Organisationskomitee der Konferenz zu senden. Zu meiner Überraschung war meine Bewerbung zufrieden 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 einen neuen Namen BIRMA erhalten und verschiedene zusätzliche (nicht so vollständig realisierte wie erwartete) Möglichkeiten erhalten -
alle Details finden Sie in meinem Bericht .
Ehrlich gesagt war es schwierig, die BIRMA 2013 als vollständig zu bezeichnen. Ehrlich gesagt, es war eine Peitsche, die sehr hackig gemacht wurde. Was den Codeteil betrifft, gab es praktisch überhaupt keine besonderen Neuerungen, abgesehen von einem eher hilflosen Versuch, eine einheitliche Syntax für den Parser zu erstellen, die anscheinend der Formatierungssprache IRBIS 64 (und sogar ISIS) mit Klammern in der Rolle zyklischer Strukturen ähnelt; warum dann schien es mir, dass es sehr cool aussieht). Der Parser stolperte hoffnungslos über diese Strudel aus den Klammern des entsprechenden Typs (da die Klammern dort die gleiche Rolle spielten, nämlich sie markierten optionale Strukturen, die beim Parsen übersprungen werden konnten). Jeder, der die damals schwer vorstellbare, ungerechtfertigte BIRMA-Syntax genauer kennenlernen möchte, verweise noch einmal auf meinen damaligen Bericht.
Im Allgemeinen habe ich, abgesehen vom Kampf mit unserem eigenen Parser, im Hinblick auf den Code dieser Version nichts mehr zu sagen - abgesehen von der umgekehrten Konvertierung der verfügbaren Quellen in C ++ unter Beibehaltung einiger typischer Merkmale von .NET-Code (um ehrlich zu sein, ist es schwer zu verstehen) was mich genau dazu veranlasste, alles zurück zu übertragen - wahrscheinlich eine Art verrückte Angst, meine Quellcodes geheim zu halten, als wäre es etwas, das mit Coca-Colas Geheimrezept vergleichbar wäre).
Vielleicht enthält diese dumme Entscheidung auch den Grund für die Schwierigkeiten beim Koppeln der resultierenden DLL mit der vorhandenen selbst erstellten Workstation-Schnittstelle für die Eingabe von Daten in den elektronischen Katalog (ja, ich habe noch keine weitere wichtige Tatsache erwähnt: Von nun an war der gesamte BIRMA-Engine-Code wie erwartet von der Schnittstelle getrennt und in die entsprechende DLL gepackt). Warum mussten Sie für diese Zwecke eine separate Workstation schreiben, die in ihrem Erscheinungsbild und in der Art der Interaktion mit dem Benutzer schamlos dieselbe „Catalogizer“ -Arbeitsstation des IRBIS 64-Systems kopierte - dies ist ein separates Problem. Kurz gesagt: Er hat meine damaligen Erfolge für das Abschlussprojekt gebührend respektiert (ansonsten war die unverdauliche Parser-Engine allein irgendwie nicht genug). Außerdem stieß ich dann auf einige Schwierigkeiten, als ich die "Catalogizer" -Workstation zusammen mit meinen eigenen Modulen implementierte, die sowohl in C ++ als auch in C # implementiert waren, und direkt an meine Engine adressierte.
Grundsätzlich seltsamerweise, aber es war dieser etwas umständliche Prototyp des zukünftigen BIRMA.NET, der für die nächsten vier Jahre zu meinem "Arbeitstier" werden sollte. Es kann nicht gesagt werden, dass ich in dieser Zeit nicht einmal versucht habe, Wege für eine neue, vollständigere Umsetzung einer langjährigen Idee zu finden. Unter anderem sollte es bereits verschachtelte zyklische Sequenzen geben, die auch optionale Elemente enthalten könnten - so wollte ich die Idee universeller Vorlagen für die bibliografische Beschreibung von Veröffentlichungen und verschiedenen anderen interessanten Dingen verwirklichen. In meiner damaligen Praxis wurde dies jedoch nur unzureichend gefordert, und die Implementierung, die ich zu diesem Zeitpunkt hatte, reichte völlig aus, um das Inhaltsverzeichnis einzuführen. Außerdem begann der Vektor der Entwicklungsrichtung unserer Bibliothek immer mehr in Richtung Digitalisierung von Museumsarchiven, Erstellung von Berichten und anderen Aktivitäten zu abweichen, die für mich von geringem Interesse waren, was mich letztendlich dazu veranlasste, es vollständig zu verlassen und denen Platz zu machen, denen es angenehmer gewesen wäre .
Paradoxerweise, aber genau nach diesen dramatischen Ereignissen, schien das BIRMA-Projekt, das zu diesem Zeitpunkt bereits alle charakteristischen Merkmale eines typischen Langzeitbaus besaß, 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 (gut, jetzt konnte ich schon raten, all dies von überall zu suchen, nämlich auf GitHub) und irgendwo in Anfang dieses Jahres stieß ich schließlich auf das entsprechende Handwerk des bekannten Salesforce-Büros unter dem unwichtigen Namen
Gorp . An sich könnte es fast alles tun, was ich von einer solchen Parser-Engine benötige - nämlich einzelne Fragmente intelligent von einer beliebigen zu isolieren, aber mit einer klaren Struktur des Textes, während es eine ziemlich leicht verdauliche Oberfläche für den Endbenutzer hat, einschließlich einer solchen klaren Entitäten als Muster, Muster und Vorkommen und gleichzeitig mit der üblichen Syntax regulärer Ausdrücke, die durch die Aufteilung in aussagekräftige semantische Gruppen zur Analyse unvergleichlich lesbarer wird.
Im Allgemeinen habe ich beschlossen, dass derselbe
Gorp (ich frage mich, was dieser Name bedeutet? Vielleicht eine Art "allgemein orientierter regulärer Parser"?) Genau das ist, wonach ich lange gesucht habe. Die sofortige Implementierung für meine eigenen Bedürfnisse hatte zwar ein derartiges Problem, dass diese Engine eine zu strikte Einhaltung der strukturellen Abfolge des Quelltextes erforderte. Bei einigen Berichten wie Protokolldateien (die von den Entwicklern als visuelle Beispiele für die Verwendung des Projekts platziert wurden) funktioniert dies einwandfrei, bei denselben Texten ist das gescannte Inhaltsverzeichnis jedoch unwahrscheinlich. Immerhin kann dieselbe Seite mit dem Inhaltsverzeichnis mit den Worten "Inhaltsverzeichnis", "Inhalt" und einigen anderen vorläufigen Beschreibungen beginnen, die wir überhaupt nicht benötigen, um die Ergebnisse der vorgeschlagenen Analyse einzufügen (und es ist auch unpraktisch, sie jedes Mal manuell abzuschneiden). Darüber hinaus kann die Seite zwischen einzelnen sich wiederholenden Elementen wie dem Namen, dem Titel und der Seitenzahl des Autors eine bestimmte Menge Müll enthalten (z. B. Bilder und nur zufällige Zeichen), was auch schön wäre, wenn man sie abschneiden könnte. Der letzte Aspekt war jedoch immer noch nicht so wichtig, aber aufgrund des ersten konnte die vorhandene Implementierung nicht von einer bestimmten Stelle aus nach den erforderlichen Strukturen im Text suchen, sondern sie nur von Anfang an verarbeiten, die angegebenen Muster dort nicht finden und ... fertig sein deine Arbeit. Offensichtlich war eine entsprechende Überarbeitung erforderlich, die es zumindest ermöglichte, einige Lücken zwischen den sich wiederholenden Strukturen zu lassen, und dies ließ mich wieder bei der Arbeit sitzen.
Ein weiteres Problem war, dass das Projekt selbst in Java implementiert wurde, und wenn ich vorhatte, ein Mittel zur Kopplung dieser Technologie mit den üblichen Anwendungen für die Eingabe von Daten in vorhandene Datenbanken (wie den Irbis-Katalogisierer) weiter zu implementieren, dann zumindest Mindestens in C # und .NET. Nicht, dass Java selbst eine schlechte Sprache gewesen wäre - nachdem ich sogar eine uninteressante Fensteranwendung darauf implementiert hatte, die die Funktionalität eines inländischen programmierbaren Rechners (als Teil eines Kursprojekts) implementiert. Ja, und in der Syntax ist es dem gleichen C-Sharpe sehr ähnlich. Nun, das ist nur ein Pluspunkt: Je einfacher es für mich ist, ein bestehendes Projekt abzuschließen. Ich wollte jedoch nicht in diese eher ungewöhnliche Welt der Fenster- (oder eher Desktop-) Java-Technologien eintauchen - am Ende wurde die Sprache selbst für eine solche Verwendung nicht „geschärft“, und ich sehnte mich überhaupt nicht nach einer Wiederholung der vorherigen Erfahrung. Vielleicht liegt es daran, dass C # in Verbindung mit WinForms viel näher an Delphi ist, was viele von uns einst begonnen haben. Glücklicherweise wurde die richtige Lösung ziemlich schnell gefunden - in der Person des
IKVM.NET- Projekts, das es einfach macht, vorhandene Java-Programme in verwalteten .NET-Code zu übersetzen. Zwar wurde das Projekt selbst zu diesem Zeitpunkt bereits von den Autoren aufgegeben, aber seine neueste Implementierung ermöglichte es mir, die erforderlichen Aktionen für die
Gorp- Quelltexte recht erfolgreich durchzuführen.
Also habe ich alle notwendigen Änderungen vorgenommen und alles in eine DLL des entsprechenden Typs eingefügt, die alle in Visual Studio erstellten Projekte für .NET Framework problemlos „abholen“ konnten. In der
Zwischenzeit habe ich eine weitere Ebene zur bequemen Darstellung der von
Gorp zurückgegebenen Ergebnisse in Form entsprechender Datenstrukturen erstellt, die in einer Tabellendarstellung bequem zu verarbeiten wären (und als Grundlage sowohl Zeilen als auch Spalten, sowohl Wörterbuchschlüssel als auch numerische Indizes). . Nun, die notwendigen Hilfsprogramme für die Verarbeitung und Anzeige der Ergebnisse wurden ziemlich schnell geschrieben.
Auch das Anpassen von Vorlagen für die neue Engine verursachte keine besonderen Komplikationen, um ihm beizubringen, wie vorhandene Beispiele gescannter Inhaltsverzeichnis-Texte zerlegt werden. Tatsächlich musste ich mich nicht einmal meinen vorherigen Leerzeichen zuwenden: Ich habe gerade alle erforderlichen Vorlagen von Grund auf neu erstellt. Wenn die Vorlagen, die für die Arbeit mit der vorherigen Version des Systems entwickelt wurden, einen ziemlich engen Rahmen für Texte festlegen, die mit ihrer Hilfe korrekt analysiert werden können, ermöglichte die neue Engine bereits die Entwicklung ziemlich universeller Vorlagen, die für mehrere Arten von Markups gleichzeitig geeignet sind. Ich habe sogar versucht, eine umfassende Vorlage für einen beliebigen Text des Inhaltsverzeichnisses zu schreiben, obwohl dies natürlich trotz all der neuen Möglichkeiten, die sich mir eröffnen, einschließlich der eingeschränkten Möglichkeit, dieselben verschachtelten Wiederholungssequenzen (wie z. B. Nachnamen und Initialen) zu implementieren mehrere Autoren hintereinander), stellte sich heraus, dass dies eine Utopie war.
Es ist möglich, dass es in Zukunft möglich sein wird, ein bestimmtes Konzept von Meta-Vorlagen zu implementieren, mit denen der Quelltext auf Übereinstimmung mit mehreren der verfügbaren Vorlagen gleichzeitig überprüft und dann gemäß den erzielten Ergebnissen mithilfe eines intelligenten Algorithmus die am besten geeignete ausgewählt werden kann. Aber jetzt machte ich mir mehr Sorgen um eine andere Frage. Solch ein Parser wie
Gorp war trotz seiner Vielseitigkeit und Modifikationen von Natur aus immer noch nicht in der Lage, eine scheinbar einfache Sache auszuführen, die mein eigener handgeschriebener Parser von der ersten Version an konnte. Er hatte nämlich die Möglichkeit, alle Fragmente, die mit der im Rahmen der verwendeten Vorlage angegebenen Maske übereinstimmen, an der richtigen Stelle zu finden und aus dem Quelltext zu extrahieren, ohne sich dafür zu interessieren, was der Text in den Zwischenräumen zwischen diesen Fragmenten enthält. Bisher habe ich die neue Engine nur geringfügig verbessert, sodass sie nach allen möglichen neuen Wiederholungen einer bestimmten Sequenz solcher Masken von der aktuellen Position aus suchen kann, sodass der Text beim Parsen von zwischen erkannten Wiederholungsstrukturen eingeschlossenen Sätzen beliebiger Zeichen möglicherweise nicht berücksichtigt wird. Dies ermöglichte es jedoch nicht, die nächste Maske unabhängig von den Suchergebnissen für das vorherige Fragment durch die entsprechende Maske zu setzen: Die Strenge der beschriebenen Struktur des Textes ließ immer noch keinen Raum für willkürliche Einschlüsse von unregelmäßigen Zeichen.
Und wenn für die Beispiele des Inhaltsverzeichnisses, auf die ich gestoßen bin, dieses Problem noch nicht so ernst zu sein schien, dann sind seine Einschränkungen hier, wenn versucht wird, den neuen Analysemechanismus auf eine ähnliche Aufgabe anzuwenden, um im Wesentlichen Website-Inhalte zu analysieren (d. H. Dasselbe Analyse) sie erschienen mit all ihren Beweisen. Schließlich ist es recht einfach, die erforderlichen Masken für Web-Markup-Fragmente festzulegen, zwischen denen sich die gesuchten Daten befinden sollten (die Sie extrahieren müssen), aber wie der Parser sofort zum nächsten ähnlichen Fragment wechseln kann, trotz aller möglichen HTML-Tags und Attribute, die passen die Lücken zwischen ihnen?
Nach
einigem Überlegen habe ich mich entschlossen, einige Dienstprogrammmuster
(% all_before) und
(% all_after) einzuführen , die dem offensichtlichen Zweck dienen, vor jedem nachfolgenden Muster (Maske) alles
wegzulassen , was im Quelltext enthalten sein kann. Wenn
(% all_before) einfach alle diese willkürlichen Einschlüsse ignorierte, erlaubte
(% all_after) im Gegenteil, sie dem gewünschten Fragment hinzuzufügen, nachdem vom vorherigen Fragment
gewechselt wurde . Es klingt ziemlich einfach, aber um dieses Konzept zu implementieren, musste ich die Gorp-Quellen erneut „durchkämmen“, um die erforderlichen Änderungen vorzunehmen, um die bereits implementierte Logik nicht zu beschädigen.
Am Ende habe ich es geschafft (obwohl sogar die allererste, wenn auch sehr fehlerhafte Implementierung meines Parsers geschrieben wurde und noch schneller - in ein paar Wochen). Von nun an hat das System ein wirklich universelles Aussehen angenommen - nicht mehr als 12 Jahre nach den ersten Versuchen, es funktionsfähig zu machen., . gorp' C#, - . , , Java. , , - (, , – ).
, , Salesforce (
Gorp ), – . , .
, Salesforce
Gorp ( , , ,
Gorp ). –
Gorp.NET .