L'histoire d'un petit projet de douze ans (sur BIRMA.NET pour la première fois et honnêtement de première main)

La naissance de ce projet peut être considérée comme une petite idée qui m’a rendu visite quelque part fin 2007, qui ne devait retrouver sa forme définitive que 12 ans plus tard (à ce stade - bien sûr, bien que la mise en œuvre actuelle, de l’avis de l’auteur, soit très satisfaisante) .

Tout a commencé avec le fait que, dans le cadre de l'accomplissement de mes fonctions officielles à la bibliothèque, j'ai attiré l'attention sur le fait que le processus de saisie des données du texte numérisé de la table des matières des publications de livres (et de musique) dans la base de données existante, apparemment, peut être grandement simplifié. et automatiser, en utilisant la propriété de l'ordre et de la répétabilité de toutes les données requises pour la saisie, telles que le nom de l'auteur de l'article (si nous parlons d'une collection d'articles), le nom de l'article (ou le sous-titre reflété dans la table des matières) et La page de la table des matières actuelle. Au début, j'étais presque convaincu qu'un système adapté à cette tâche pouvait être facilement trouvé sur Internet. Quand une certaine surprise a été causée par le fait que je n'ai pas pu trouver un tel projet, j'ai décidé d'essayer de le mettre en œuvre par moi-même.

Après un temps assez court, le premier prototype a commencé à fonctionner, que j'ai immédiatement commencé à utiliser dans mes activités quotidiennes, en le déboguant simultanément avec tous les exemples qui me venaient à la main. Heureusement, dans mon lieu de travail habituel, où je n'étais en aucun cas un programmeur, j'étais toujours en mesure de m'en tirer avec des «temps d'arrêt» visibles au travail, pendant lesquels je travaillais dur pour déboguer mon idée originale - une chose presque impensable dans les réalités d'aujourd'hui, impliquant des rapports quotidiens sur le travail effectué pendant la journée. Le processus de polissage du programme a pris au total pas moins d'un an, mais même après cela, le résultat ne pouvait guère être qualifié de complètement réussi - trop de concepts différents qui n'étaient pas tout à fait intelligibles pour la mise en œuvre y étaient initialement définis: éléments facultatifs qui peuvent être ignorés; vue dominante des éléments (dans le but de remplacer les résultats de recherche des éléments précédents); même votre propre tentative d'implémenter quelque chose comme des expressions régulières (ayant une syntaxe distincte). Je dois dire qu'avant cela, j'ai réussi à jeter un peu la programmation (pendant environ 8 ans, sinon plus), donc la nouvelle opportunité d'appliquer mes compétences à une tâche intéressante et nécessaire a complètement capté mon attention. Il n'est pas surprenant que le code source résultant - en l'absence d'approches intelligibles pour le concevoir pour moi - soit rapidement devenu un méli-mélo inimaginable de pièces disparates en langage C avec certains éléments C ++ et certains aspects de la programmation visuelle (il a été initialement décidé d'utiliser un système de conception tel que Borland C ++ Builder - «presque Delphi, mais en C»). Mais tout cela a finalement porté ses fruits dans l'automatisation des activités quotidiennes de notre bibliothèque.

Dans le même temps, j'ai décidé, au cas où, de suivre des formations pour les développeurs de logiciels professionnels. Je ne sais pas s'il est possible d'apprendre vraiment "à partir d'un programmeur" à partir de zéro, mais compte tenu des compétences que j'avais déjà à l'époque, j'ai pu maîtriser des technologies un peu plus avancées comme C #, Visual Studio pour développer sous. NET, ainsi que certaines des technologies liées à Java, HTML et SQL. Toute la formation a duré deux ans au total et a servi de point de départ à un autre de mes projets, qui s'est finalement étendu sur plusieurs années - mais c'est déjà un sujet pour une publication séparée. Ici, il ne sera pertinent de noter que j'ai tenté d'adapter l'expérience que j'avais déjà sur le projet décrit pour créer une application de fenêtre à part entière en C # et WinForms qui implémente les fonctionnalités nécessaires, et la mettre à la base du projet de graduation à venir.
Au fil du temps, cette idée a commencé à sembler digne d'être exprimée lors de ces conférences annuelles avec la participation de représentants de diverses bibliothèques, telles que LIBCOM et CRIMEA. L'idée est oui, mais en aucun cas ma réalisation de cette époque. Ensuite, j'ai aussi espéré, entre autres, que quelqu'un le réécrirait en utilisant des approches plus compétentes. D'une manière ou d'une autre, en 2013, j'ai décidé de rédiger un rapport sur mes travaux préliminaires et de l'envoyer au comité d'organisation de la conférence avec une demande de subvention pour participer à la conférence. À ma grande surprise, ma candidature a été satisfaite et j'ai commencé à apporter quelques améliorations au projet afin de le préparer pour la présentation à la conférence.

À ce moment-là, le projet avait déjà reçu un nouveau nom BIRMA, acquis diverses opportunités supplémentaires (pas tellement pleinement réalisées que prévu) - tous les détails peuvent être trouvés dans mon rapport .

Franchement, le BIRMA 2013 était difficile d'appeler quelque chose de complet; franchement, c'était un fouet fait de bricolage très hacky. En ce qui concerne la partie code, il n'y a eu pratiquement aucune innovation particulière, à part la tentative plutôt impuissante de créer une sorte de syntaxe unifiée pour l'analyseur, qui en apparence ressemble au langage de formatage IRBIS 64 (et, en fait, même ISIS, avec des parenthèses dans le rôle de structures cycliques; pourquoi alors il me semblait que ça avait l'air très cool). L'analyseur a désespérément trébuché sur ces tourbillons à partir des parenthèses du type correspondant (puisque les parenthèses y jouaient le même rôle, à savoir, elles marquaient des structures facultatives qui pouvaient être ignorées pendant l'analyse). Tous ceux qui veulent se familiariser plus en détail avec la syntaxe BIRMA injustifiée alors difficile à imaginer, je me réfère à nouveau à mon rapport de l'époque.

En général, à l'exception de la lutte avec notre propre analyseur, alors en ce qui concerne le code de cette version, je n'ai rien de plus à dire - à l'exception de la conversion inverse des sources disponibles en C ++ avec préservation de certaines caractéristiques typiques du code .NET (pour être honnête, il est difficile de comprendre ce qui m'a exactement incité à tout transférer - probablement une sorte de peur farfelue de garder mes codes sources secrets, comme si c'était quelque chose d'équivalent à la recette secrète de Coca-Cola).

Peut-être que cette décision stupide contient également la raison des difficultés à associer la DLL résultante avec l'interface de station de travail self-made existante pour entrer des données dans le catalogue électronique (oui, je n'ai pas mentionné encore un autre fait important: à partir de maintenant, tout le code moteur BIRMA était comme prévu, séparé de l'interface et empaqueté dans la DLL appropriée). Pourquoi avez-vous eu besoin d'écrire un poste de travail séparé à ces fins, qui de toute façon, dans son apparence et dans la manière d'interagir avec l'utilisateur, a copié sans vergogne le même poste de travail «Catalogizer» du système IRBIS 64 - c'est un problème distinct. En bref: il a respecté mes réalisations de l'époque pour le projet de remise des diplômes (sinon le moteur d'analyse indestructible à lui seul n'était en quelque sorte pas suffisant). De plus, j'ai rencontré quelques difficultés lors de l'implémentation du couplage de la station de travail «Catalogizer» avec mes propres modules implémentés à la fois en C ++ et C #, et en m'adressant directement à mon moteur.

En général, curieusement, mais c'était ce prototype plutôt maladroit du futur BIRMA.NET qui était destiné à devenir mon «cheval de bataille» pour les quatre prochaines années. Cela ne veut pas dire que pendant ce temps je n'ai même pas essayé de trouver des moyens pour une nouvelle mise en œuvre plus complète d'une idée ancienne. Parmi les autres innovations, il aurait dû déjà y avoir des séquences cycliques imbriquées, qui pourraient également inclure des éléments facultatifs - c'est ainsi que j'allais réaliser l'idée de modèles universels pour la description bibliographique des publications et diverses autres choses intéressantes. Cependant, dans ma pratique à l'époque, tout cela était mal exigé, et l'implémentation que j'avais à l'époque était assez suffisante pour introduire la table des matières. De plus, le vecteur de la direction du développement de notre bibliothèque a commencé à dévier de plus en plus vers la numérisation des archives du musée, générant des rapports et d'autres activités qui m'intéressaient peu, ce qui au final m'a fait le quitter complètement, laissant la place à ceux qui auraient été plus satisfaits de tout cela .

Paradoxalement, mais précisément après ces événements dramatiques, le projet BIRMA, qui à l'époque possédait déjà toutes les caractéristiques d'une construction typique à long terme, semblait commencer à reprendre sa nouvelle vie tant attendue! J'avais plus de temps libre pour des pensées inutiles, j'ai recommencé à parcourir le World Wide Web à la recherche de quelque chose de similaire (bon, maintenant je pouvais déjà deviner chercher tout cela n'importe où, à savoir sur GitHub), et quelque part dans Au début de cette année, j'ai finalement découvert le métier correspondant du célèbre bureau Salesforce sous le nom sans importance de Gorp . En lui-même, il pourrait faire presque tout ce dont j'avais besoin à partir d'un tel moteur d'analyse - à savoir, isoler intelligemment des fragments individuels d'un arbitraire, mais avec une structure claire du texte, tout en ayant une interface assez digeste pour l'utilisateur final, y compris un tel clair entités en tant que modèle, modèle et occurrence, et en même temps impliquant la syntaxe habituelle des expressions régulières, qui devient incomparablement plus lisible en se décomposant en groupes sémantiques significatifs pour l'analyse.

En général, j'ai décidé que ce même Gorp (je me demande ce que signifie ce nom? Peut-être un "analyseur régulier orienté général"?) Est exactement ce que je cherchais depuis longtemps. Certes, sa mise en œuvre immédiate pour mes propres besoins avait un tel problème que ce moteur exigeait une adhésion trop stricte à la séquence structurelle du texte source. Pour certains rapports tels que les fichiers journaux (à savoir, ils ont été placés par les développeurs comme exemples visuels de l'utilisation du projet), cela fonctionnera correctement, mais pour les mêmes textes, la table des matières numérisée est peu probable. Après tout, la même page avec la table des matières peut commencer par les mots "Table des matières", "Contenu" et quelques autres descriptions préliminaires que nous n'avons pas du tout besoin de mettre dans les résultats de l'analyse proposée (et il est également gênant de les couper manuellement à chaque fois). En outre, entre des éléments répétés individuels, tels que le nom, le titre et le numéro de page de l'auteur, la page peut contenir une certaine quantité de déchets (par exemple, des images et uniquement des caractères aléatoires), ce qui serait également bien de pouvoir couper. Cependant, le dernier aspect n'était toujours pas aussi significatif, mais en vertu du premier, l'implémentation existante ne pouvait pas commencer à rechercher les structures nécessaires dans le texte à partir d'un endroit spécifique, mais au lieu de cela, il les avait traitées dès le début, n'y avait pas trouvé les modèles spécifiés et ... terminé votre travail. De toute évidence, une révision appropriée était nécessaire, ce qui permettrait au moins de laisser des lacunes entre les structures répétitives, et cela m'a fait me rasseoir au travail.

Un autre problème était que le projet lui-même était implémenté en Java, et si je prévoyais d'implémenter davantage certains moyens d'interfacer cette technologie avec les applications habituelles pour entrer des données dans des bases de données existantes (comme le catalogueur Irbis), alors au moins moins le faire en C # et .NET. Non pas que Java lui-même était un mauvais langage - une fois que j'ai même implémenté une application de fenêtre sans intérêt qui implémente les fonctionnalités d'une calculatrice programmable domestique (dans le cadre d'un projet de cours). Oui, et dans la syntaxe, il est très similaire au même C-sharpe. Eh bien, ce n'est qu'un plus: plus il me sera facile de finaliser un projet existant. Cependant, je ne voulais pas me plonger dans ce monde plutôt inhabituel des technologies Java de fenêtre (ou plutôt de bureau) - au final, le langage lui-même n'a pas été "affiné" pour une telle utilisation, et je n'ai pas du tout attendu une répétition de l'expérience précédente. C'est peut-être parce que C # en conjonction avec WinForms est beaucoup plus proche de Delphi, que beaucoup d'entre nous ont déjà lancé. Heureusement, la bonne solution a été trouvée assez rapidement - en la personne du projet IKVM.NET , ce qui facilite la traduction des programmes Java existants en code .NET géré. Certes, le projet lui-même était déjà abandonné par les auteurs à l'époque, mais sa dernière implémentation m'a permis de faire avec succès les actions nécessaires pour les textes sources de Gorp .

J'ai donc apporté toutes les modifications nécessaires et j'ai tout placé dans une DLL du type approprié, que tout projet pour le .NET Framework créé dans Visual Studio pouvait facilement «récupérer». En attendant , j'ai créé une autre couche pour une présentation pratique des résultats retournés par Gorp , sous la forme de structures de données correspondantes qui seraient pratiques à traiter dans une représentation sous forme de tableau (et en prenant comme base à la fois les lignes et les colonnes; les clés de dictionnaire et les indices numériques) . Eh bien, les utilitaires nécessaires pour le traitement et l'affichage des résultats ont été écrits assez rapidement.

De plus, le processus d'adaptation des modèles pour le nouveau moteur n'a pas entraîné de complications particulières afin de lui apprendre à démonter les échantillons existants de textes de table des matières numérisés. En fait, je n'ai même pas eu à me tourner vers mes blancs précédents: je viens de créer tous les modèles nécessaires à partir de zéro. De plus, si les modèles conçus pour fonctionner avec la version précédente du système définissaient un cadre assez étroit pour les textes qui pouvaient être correctement analysés avec leur aide, le nouveau moteur permettait déjà le développement de modèles assez universels adaptés à plusieurs types de balisage à la fois. J'ai même essayé d'écrire un modèle complet pour n'importe quel texte de table des matières arbitraire, bien que, bien sûr, même avec toutes les nouvelles possibilités qui s'ouvrent pour moi, y compris, en particulier, la capacité limitée à implémenter toutes les mêmes séquences répétitives imbriquées (comme, par exemple, les noms de famille et les initiales plusieurs auteurs d'affilée), cela s'est avéré être une utopie.

Il est possible qu'à l'avenir, il soit possible de mettre en œuvre un certain concept de méta-modèles qui peuvent vérifier le texte source pour la conformité avec plusieurs des modèles disponibles à la fois, puis, conformément aux résultats obtenus, choisir le plus approprié en utilisant un algorithme intelligent. Mais maintenant, j'étais plus préoccupé par une autre question. Un analyseur tel que Gorp , malgré toute sa polyvalence et les modifications que j'ai faites, était encore par sa nature incapable d'exécuter une chose apparemment simple que mon propre analyseur manuscrit a pu faire depuis la toute première version. À savoir: il avait la possibilité de trouver et d'extraire du texte source tous les fragments qui correspondent au masque spécifié dans le cadre du modèle utilisé au bon endroit, sans être du tout intéressé par ce que le texte contient dans les espaces entre ces fragments. Jusqu'à présent, je n'ai que légèrement amélioré le nouveau moteur, lui permettant de rechercher toutes les nouvelles répétitions possibles d'une séquence donnée de ces masques à partir de la position actuelle, laissant la possibilité pour le texte d'être complètement ignoré lors de l'analyse des ensembles de caractères arbitraires inclus entre les structures répétitives détectées. Cependant, cela n'a pas permis de définir le masque suivant quels que soient les résultats de recherche du fragment précédent par le masque qui lui correspond: la rigueur de la structure décrite du texte n'a toujours pas laissé de place pour des inclusions arbitraires de caractères irréguliers.

Et si pour les exemples de table des matières qui me sont apparus, ce problème ne semblait pas encore si grave, alors lorsque vous essayez d'appliquer le nouveau mécanisme d'analyse à une tâche similaire essentiellement pour analyser le contenu du site Web (c'est-à-dire la même analyse), ses limites sont ici ils sont apparus avec toutes leurs preuves. Après tout, il est assez simple de définir les masques nécessaires pour les fragments de balisage Web, entre lesquels devraient être les données que nous recherchons (que vous devez extraire), mais comment faire en sorte que l'analyseur passe immédiatement au fragment similaire suivant, malgré toutes les balises HTML et les attributs possibles qui peuvent tenir dans les écarts entre eux?

Après un peu de réflexion, j'ai décidé d'introduire quelques modèles d'utilité (% all_before) et (% all_after) , qui ont pour objectif évident de garantir l'omission de tout ce qui peut être contenu dans le texte source avant tout modèle ultérieur (masque). De plus, si (% all_before) ignorait simplement toutes ces inclusions arbitraires, alors (% all_after) , au contraire, permettait de les ajouter au fragment souhaité après avoir basculé du fragment précédent. Cela semble assez simple, mais pour implémenter ce concept, j'ai dû «peigner» à nouveau les sources de gorp pour apporter les modifications nécessaires afin de ne pas briser la logique déjà implémentée.En fin de compte, j'ai réussi à le faire (même si la toute première implémentation, bien que très boguée, de mon analyseur a été écrite et encore plus rapidement - en quelques semaines). Désormais, le système a pris un aspect véritablement universel - pas plus de 12 ans après les premières tentatives pour le faire fonctionner.

Bien sûr, ce n'est pas le rêve ultime. Vous pouvez toujours réécrire complètement l'analyseur des modèles de gorp en C # en utilisant l'une des bibliothèques disponibles pour implémenter la grammaire gratuite. Je pense que le code devrait être grandement simplifié, et cela supprimera l'héritage sous la forme de sources existantes en Java. Mais avec le type de moteur existant, il est également tout à fait possible de faire diverses choses intéressantes, y compris une tentative de mise en œuvre des méta-modèles que j'ai déjà mentionnés, sans parler de l'analyse de diverses données de divers sites Web (cependant, je n'exclue pas que les outils logiciels spécialisés existants soient plus appropriés pour cela. - Je n'avais tout simplement pas l'expérience pertinente pour les utiliser).

Soit dit en passant, cet été, j'ai déjà reçu une invitation par courrier électronique d'une entreprise qui utilise la technologie Salesforce (le développeur du Gorp original ) pour passer une interview pour d'autres travaux à Riga. Malheureusement, pour le moment, je ne suis pas prêt pour de telles délocalisations.

La deuxième partie décrit plus en détail la technologie de compilation et d'analyse ultérieure des modèles à l'aide de l'exemple d'implémentation utilisé dans Salesforce Gorp (mes propres ajouts, à l'exception de quelques mots de service déjà décrits, ne modifient pratiquement pas la syntaxe du modèle lui-même, donc presque toute la documentation du système d'origine GorpConvient pour ma version). Vous y trouverez un exemple de code pour interagir avec ce moteur et un lien vers le référentiel de ma version - Gorp.NET .

Source: https://habr.com/ru/post/fr474536/


All Articles