On iki yıllık küçük bir projenin hikayesi (BIRMA.NET hakkında ilk kez ve açıkçası ilk elden)

Bu projenin doğuşu, 2007'nin sonlarında aklıma gelen küçük bir fikir olarak düşünülebilir ve nihai şeklini yalnızca 12 yıl sonra bulması bekleniyordu (bu noktada - tabii ki mevcut uygulamaya göre, yazar için oldukça tatmin edicidir).

Her şey, kütüphanedeki o zamanki resmi görevlerimi yerine getirme sürecinde, kitap (ve müzik) yayınlarının içindekiler tablosunun taranmış metninden veri girme sürecinin mevcut veritabanına girilmesine dikkat çekmemle başladı, Görünüşe göre, makalenin yazarının adı (bir makale koleksiyonundan bahsediyorsak), makalenin başlığı gibi girdi için gerekli tüm verilerin düzenliliği ve tekrarlanabilirliği özelliğinden yararlanılarak önemli ölçüde basitleştirilebilir ve otomatikleştirilebilir. makale (veya içindekiler bölümünde yansıtılan alt başlık) ve mevcut içindekiler öğesinin sayfa numarası. İlk başta, bu görevi yerine getirmeye uygun bir sistemin internette kolayca bulunabileceğine neredeyse ikna olmuştum. Böyle bir proje bulamadığım için biraz şaşkınlık yaşayınca, bunu kendi başıma hayata geçirmeye karar verdim.

Oldukça kısa bir süre sonra, hemen günlük aktivitelerimde kullanmaya başladığım ilk prototip, elime gelen tüm örnekler üzerinde eş zamanlı olarak hata ayıklayarak çalışmaya başladı. Neyse ki, hiçbir şekilde programcı olmadığım her zamanki iş yerimde, işimde hala gözle görülür "kesinti süresinden" kurtuldum, bu sırada beyin çocuğumda yoğun bir şekilde hata ayıklama yapıyordum - mevcut gerçekliklerde neredeyse düşünülemez bir şey, bu da ima ediyor Gün içinde yapılan çalışmalara ilişkin günlük raporlar. Programın iyileştirilmesi süreci toplamda yaklaşık bir yıldan az sürmedi, ancak bundan sonra bile sonucun tamamen başarılı olduğu söylenemezdi - başlangıçta uygulama için tamamen anlaşılır olmayan çok fazla farklı kavram ortaya konuldu: isteğe bağlı unsurlar atlanabilir; öğelerin ileriye doğru görüntülenmesi (önceki öğelerin arama sonuçlarına yerleştirilmesi amacıyla); hatta düzenli ifadeler (benzersiz bir sözdizimine sahip) gibi bir şeyi uygulama girişimimiz bile. Bundan önce programlamayı bir şekilde bıraktığımı söylemeliyim (yaklaşık 8 yıl boyunca, hatta daha fazla), bu nedenle becerilerimi ilginç ve gerekli bir göreve uygulama fırsatı tamamen dikkatimi çekti. Sonuçta ortaya çıkan kaynak kodunun (benim açımdan tasarımına yönelik net bir yaklaşımın yokluğunda) C++'ın bazı öğeleri ve görsel programlamanın bazı yönleriyle (başlangıçta Borland C++ Builder - “neredeyse Delphi, ancak C'de”) gibi bir tasarım sisteminin kullanılmasına karar verildi. Ancak tüm bunlar sonuçta kütüphanemizin günlük faaliyetlerinin otomatikleştirilmesinde meyve verdi.

Aynı zamanda ne olur ne olmaz diye profesyonel yazılımcı yetiştirmeye yönelik kurslar almaya karar verdim. Orada "programcı olmayı" sıfırdan öğrenmenin gerçekten mümkün olup olmadığını bilmiyorum, ancak o zamanlar sahip olduğum becerileri hesaba katarsam, o zamana kadar daha alakalı olan teknolojilerde bir şekilde ustalaşabildim, örneğin C# gibi, .NET altında geliştirme için Visual Studio'nun yanı sıra Java, HTML ve SQL ile ilgili bazı teknolojiler. Eğitimin tamamı toplam iki yıl sürdü ve birkaç yıla yayılan başka bir projemin başlangıç ​​noktası oldu - ancak bu ayrı bir yayının konusu. Burada, C# ve WinForms'ta gerekli işlevselliği uygulayan tam teşekküllü bir pencere uygulaması oluşturmak ve bunu temel olarak kullanmak için açıklanan projede halihazırda sahip olduğum gelişmeleri uyarlamaya çalıştığımı belirtmek yerinde olacaktır. Yaklaşan diploma projesi.
Zamanla bu fikir bana, “LIBKOM” ve “CRIMEA” gibi çeşitli kütüphanelerin temsilcilerinin katıldığı yıllık konferanslarda dile getirilmeye değer görünmeye başladı. Fikir evet ama o zamanlar bunu uygulamam değildi. Sonra birisinin bunu daha yetkin yaklaşımlar kullanarak yeniden yazacağını da umdum. Öyle ya da böyle, 2013 yılına kadar ön çalışmamla ilgili bir rapor yazıp bunu konferansa katılım hibe başvurusuyla birlikte Konferans Düzenleme Komitesine göndermeye karar verdim. Şaşırtıcı bir şekilde başvurum onaylandı ve projeyi konferansta sunulmak üzere hazırlamak için bazı iyileştirmeler yapmaya başladım.

O zamana kadar, proje zaten BIRMA olarak yeni bir isim almış ve çeşitli ek (tam olarak uygulanmamış, daha ziyade varsayılmış) yetenekler edinmişti - tüm detayları raporumda bulabilirsiniz.

Dürüst olmak gerekirse BIRMA 2013'ü eksiksiz olarak adlandırmak zordu; Açıkça söylemek gerekirse, aceleyle yapılmış son derece beceriksiz bir zanaattı. Kod açısından, görünüşte IRBIS 64 biçimlendirme dilini (ve aslında aynı zamanda IŞİD sistemini) anımsatan, ayrıştırıcı için bir tür birleşik sözdizimi oluşturmaya yönelik oldukça çaresiz bir girişim dışında, pratikte hiçbir özel yenilik yoktu. döngüsel yapılar olarak parantezlerle; neden O zamanlar oldukça havalı göründüğünü düşünmüştüm). Ayrıştırıcı umutsuzca bu uygun türdeki parantez çemberlerine rastladı (çünkü parantezler başka bir rol oynadı, yani ayrıştırma sırasında atlanabilecek isteğe bağlı yapıları işaretlediler). BIRMA'nın o zamanlar hayal edilmesi zor, gerekçesiz sözdizimini daha ayrıntılı olarak tanımak isteyen herkesi o zamanki raporuma bir kez daha yönlendiriyorum.

Genel olarak, kendi çözümleyicimle uğraşmanın dışında, bu sürümün koduyla ilgili söyleyecek başka bir şeyim yok - .NET kodunun bazı tipik özelliklerini korurken mevcut kaynakların C++'a ters dönüştürülmesi dışında (dürüst olmak gerekirse, bu beni her şeyi geri almaya iten şeyin tam olarak ne olduğunu anlamak zor - muhtemelen kaynak kodlarımı gizli tutma konusundaki aptalca bir korku, sanki Coca-Cola'nın gizli tarifine eşdeğer bir şeymiş gibi).

Belki de bu aptalca karar, ortaya çıkan DLL kütüphanesini, elektronik kataloğa veri girmek için ev yapımı bir iş istasyonunun mevcut arayüzü ile eşleştirmedeki zorlukların nedenidir (evet, başka bir önemli gerçekten bahsetmedim: bundan sonra hepsi BIRMA “motorunun” kodu beklendiği gibi oldu, arayüz kısmından ayrıldı ve uygun DLL'de paketlendi). Bu amaçlar için neden ayrı bir iş istasyonu yazmak gerekliydi ki, bu, görünümü ve kullanıcıyla etkileşim yöntemi açısından, IRBIS 64 sisteminin aynı "Kataloglayıcı" iş istasyonunu utanmadan kopyaladı - bu ayrı bir soru. Kısacası: mezuniyet projem için o zamanki gelişmelerime gerekli sağlamlığı verdi (aksi halde sindirilemeyen ayrıştırıcı motoru tek başına yeterli değildi). Ek olarak, Cataloger iş istasyonunun arayüzünü hem C++ hem de C#'ta uygulanan kendi modüllerimle uygulamada ve motoruma doğrudan erişimde bazı zorluklarla karşılaştım.

Genel olarak, tuhaf bir şekilde, önümüzdeki dört yıl boyunca benim "beygirim" olmaya aday olan, gelecekteki BIRMA.NET'in bu oldukça hantal prototipiydi. Bu süre zarfında en azından uzun süredir devam eden bir fikrin yeni, daha eksiksiz bir şekilde uygulanmasının yollarını bulmaya çalışmadığım söylenemez. Diğer yeniliklerin yanı sıra, isteğe bağlı unsurları içerebilecek iç içe geçmiş döngüsel diziler zaten mevcut olmalıydı; yayınların bibliyografik açıklamaları ve diğer çeşitli ilginç şeyler için evrensel şablonlar fikrini bu şekilde hayata geçirecektim. Ancak o dönemdeki pratik faaliyetlerimde tüm bunlar pek talep görmüyordu ve o dönemde yaptığım uygulama, içindekiler tablosuna girmek için oldukça yeterliydi. Ayrıca kütüphanemizin gelişim vektörü, müze arşivlerinin dijitalleştirilmesine, raporlamaya ve beni pek ilgilendirmeyen diğer faaliyetlere doğru giderek daha fazla sapmaya başladı ve bu da sonunda beni sonunda onu terk etmeye zorladı ve yerini alacak olanlara bıraktı. tüm bunlardan daha memnun ol.

Paradoksal olarak, o zamanlar tipik bir uzun vadeli inşaat projesinin tüm karakteristik özelliklerine sahip olan BIRMA projesi, bu dramatik olayların ardından, uzun zamandır beklenen yeni hayatına başlamaya başlamış gibi görünüyordu! Boş düşünceler için daha fazla boş zamanım oldu, benzer bir şey bulmak için yine World Wide Web'i taramaya başladım (neyse ki, tüm bunları sadece herhangi bir yerde değil, GitHub'da da arayacağımı zaten tahmin edebiliyordum) ve At'ta bir yerde. Bu yılın başında nihayet tanınmış Salesforce şirketinin önemsiz bir isimle ilgili bir ürünüyle karşılaştım. gorp. Kendi başına, böyle bir ayrıştırıcı motordan ihtiyacım olan hemen hemen her şeyi yapabilirdi - yani, bireysel parçaları rastgele, ancak açıkça yapılandırılmış metinden akıllıca izole ederken, son kullanıcı için oldukça kullanıcı dostu bir arayüze sahipken, aşağıdaki gibi anlaşılabilir özler de dahil olmak üzere, bir kalıp, şablon ve oluşum ve aynı zamanda ayrıştırma için belirlenmiş anlamsal gruplara bölünme nedeniyle kıyaslanamayacak kadar daha okunaklı hale gelen normal ifadelerin tanıdık sözdizimini kullanmak.

Genel olarak bunun bu olduğuna karar verdim gorp (Bu ismin ne anlama geldiğini merak ediyorum. Belki bir tür “genel odaklı düzenli ayrıştırıcı”?) – tam da uzun zamandır aradığım şey. Doğru, kendi ihtiyaçlarım için derhal uygulanmasında öyle bir sorun vardı ki, bu motor, kaynak metnin yapısal sırasına çok sıkı bağlı kalmayı gerektiriyordu. Günlük dosyaları gibi bazı raporlar için (yani geliştiriciler tarafından projenin kullanımının açık örnekleri olarak yerleştirildiler), bu oldukça uygundur, ancak taranan içindekiler tablolarının aynı metinleri için bu pek olası değildir. Sonuçta, içindekiler tablosunun bulunduğu aynı sayfa, "İçindekiler", "İçindekiler" sözcükleriyle ve amaçlanan analizin sonuçlarına yerleştirmemize gerek olmayan diğer ön açıklamalarla başlayabilir (ve bunları manuel olarak kesebilir) her seferinde de sakıncalıdır). Ek olarak, yazarın adı, başlığı ve sayfa numarası gibi tekrar eden tek tek öğeler arasında sayfa, belirli miktarda çöp (örneğin çizimler ve yalnızca rastgele karakterler) içerebilir; bunları da ortadan kaldırabilmek güzel olurdu. ayırmak. Ancak son husus henüz o kadar önemli değildi, ancak birincisinden dolayı mevcut uygulama metindeki gerekli yapıları belirli bir yerden aramaya başlayamadı, bunun yerine onu en baştan basitçe işledi, aradığı metni bulamadı. orada kalıpları belirledim ve... işime son verdim. Açıkçası, yinelenen yapılar arasında en azından biraz boşluk bırakmak için bazı ince ayarlar yapılması gerekiyordu ve bu beni işime geri döndürdü.

Diğer bir sorun, projenin kendisinin Java'da uygulanmasıydı ve eğer gelecekte bu teknolojiyi mevcut veritabanlarına (Irbis'in "Kataloglayıcısı" gibi) veri girmek için tanıdık uygulamalarla arayüz oluşturmanın bazı yollarını uygulamayı planlıyorsam, o zaman en azından En azından bunu C# ve .NET'te yapın. Java'nın kendisi kötü bir dil değil; hatta bir keresinde onu, evde programlanabilir bir hesap makinesinin işlevselliğini uygulayan ilginç bir pencere uygulamasını uygulamak için bile kullandım (bir kurs projesinin parçası olarak). Ve sözdizimi açısından aynı C-diyez'e çok benzer. Bu sadece bir artı: Mevcut bir projeyi sonuçlandırmak benim için o kadar kolay olacak. Bununla birlikte, pencere (veya daha doğrusu masaüstü) Java teknolojilerinin bu oldukça alışılmadık dünyasına tekrar dalmak istemedim - sonuçta, dilin kendisi bu tür bir kullanım için "özelleştirilmedi" ve hiç de tekrarlanmasını istemedim. önceki deneyim. Belki de bunun nedeni WinForms ile birlikte C#'ın çoğumuzun bir zamanlar başladığı Delphi'ye çok daha yakın olmasıdır. Neyse ki gerekli çözüm oldukça hızlı bir şekilde bulundu - proje şeklinde İKVM.NET, mevcut Java programlarının yönetilen .NET koduna çevrilmesini kolaylaştırır. Doğru, projenin kendisi o zamana kadar yazarlar tarafından zaten terk edilmişti, ancak son uygulaması kaynak metinler için gerekli eylemleri oldukça başarılı bir şekilde gerçekleştirmeme izin verdi gorp.

Böylece gerekli tüm değişiklikleri yaptım ve hepsini, Visual Studio'da oluşturulan .NET Framework için herhangi bir proje tarafından kolayca "alınabilecek" uygun türde bir DLL'de birleştirdim. Bu arada, döndürülen sonuçların uygun şekilde sunulması için başka bir katman oluşturdum gorp, bir tablo görünümünde işlenmesi uygun olacak karşılık gelen veri yapıları biçiminde (hem satırlar hem de sütunlar temel alınarak; hem sözlük anahtarları hem de sayısal dizinler). Sonuçların işlenmesi ve görüntülenmesi için gerekli yardımcı programlar oldukça hızlı bir şekilde yazılmıştır.

Ayrıca, içindekiler tablosundaki taranmış metinlerin mevcut örneklerini ayrıştırmayı öğretmek amacıyla şablonları yeni motor için uyarlama süreci de herhangi bir özel komplikasyona neden olmadı. Aslında önceki şablonlarıma başvurmama bile gerek yoktu: Gerekli tüm şablonları sıfırdan oluşturdum. Dahası, sistemin önceki sürümüyle çalışmak üzere tasarlanan şablonlar, onların yardımıyla doğru bir şekilde ayrıştırılabilecek metinler için oldukça dar bir çerçeve oluşturuyorsa, yeni motor, çeşitli işaretleme türlerine uygun, oldukça evrensel şablonlar geliştirmeyi zaten mümkün kıldı. bir kere. Hatta herhangi bir rastgele içindekiler metni metni için bir tür kapsamlı şablon yazmaya bile çalıştım, ancak elbette, özellikle aynı iç içe tekrarlanan dizileri uygulama konusundaki sınırlı yetenek de dahil olmak üzere benim için açılan tüm yeni olasılıklara rağmen ( örneğin birkaç yazarın soyadları ve baş harflerinin arka arkaya yazılması gibi), bunun bir ütopya olduğu ortaya çıktı.

Belki gelecekte, kaynak metnin mevcut şablonların birçoğuna uygunluğunu aynı anda kontrol edebilecek ve daha sonra elde edilen sonuçlara göre seçebilecek belirli bir meta şablon konseptini uygulamak mümkün olacaktır. bir çeşit akıllı algoritma kullanan en uygun olanı. Ama şimdi başka bir soruyla daha çok ilgileniyordum. Gibi bir ayrıştırıcı gorp, tüm çok yönlülüğüne ve yaptığım değişikliklere rağmen, kendi yazdığım ayrıştırıcımın ilk versiyondan itibaren yapabildiği görünüşte basit bir şeyi yapma konusunda doğası gereği hala yetersizdi. Yani: verilen metnin bu parçalar arasındaki boşluklarda ne içerdiğiyle hiç ilgilenmeden, doğru yerde kullanılan şablonda belirtilen maskeyle eşleşen tüm parçaları kaynak metinden bulma ve çıkarma becerisine sahipti. Şu ana kadar, yeni motoru çok az geliştirdim; mevcut konumdan bu tür maskelerin belirli bir dizisinin olası tüm yeni tekrarlarını aramasına izin vererek, tamamen rastgele karakter kümelerinin metninde var olma olasılığını bıraktım. ayrıştırmada hesaba katılmayan, tespit edilen yinelenen yapılar arasında yer alan. Ancak bu, karşılık gelen maskeyi kullanarak önceki parçayı aramanın sonuçlarından bağımsız olarak bir sonraki maskeyi ayarlamayı mümkün kılmadı: açıklanan metin yapısının katılığı, düzensiz karakterlerin keyfi olarak eklenmesine hala yer bırakmıyordu.

Ve karşılaştığım içindekiler tablosu örnekleri için bu sorun henüz o kadar ciddi görünmüyorsa, o zaman bir web sitesinin içeriğini ayrıştırma gibi benzer bir göreve (yani aynı ayrıştırma) yeni bir ayrıştırma mekanizması uygulamaya çalışırken, onun sınırlamalar burada tüm açıklığıyla ortaya çıktı. Sonuçta, aradığımız verilerin (çıkarılması gereken) arasında yer alması gereken web işaretleme parçaları için gerekli maskeleri ayarlamak oldukça kolaydır, ancak ayrıştırıcıyı hemen bir sonraki adıma geçmeye nasıl zorlayabiliriz? Aralarındaki boşluklara yerleştirilebilecek tüm olası etiketlere ve HTML özelliklerine rağmen benzer bir parça mı var?

Biraz düşündükten sonra birkaç hizmet modelini tanıtmaya karar verdim (%all_before) и (%all_after)Kaynak metinde bulunabilecek her şeyin, onları takip eden herhangi bir kalıptan (maske) önce atlanmasını sağlamak gibi bariz bir amaca hizmet eder. Üstelik eğer (%all_before) tüm bu keyfi eklemeleri görmezden geldin, sonra (%all_after)tam tersine önceki parçadan hareket ederek istenilen parçaya eklenmelerine olanak sağladı. Oldukça basit gibi görünüyor, ancak bu konsepti uygulamak için, zaten uygulanan mantığı bozmamak için gerekli değişiklikleri yapmak amacıyla gorp kaynaklarını tekrar taramak zorunda kaldım. Sonunda bunu yapmayı başardık (her ne kadar ilk, çok hatalı da olsa, ayrıştırıcımın uygulanması bile birkaç hafta içinde ve hatta daha hızlı yazıldı). Şu andan itibaren sistem gerçek anlamda evrensel bir biçime büründü; ilk işlemeye yönelik girişimlerden en az 12 yıl sonra.

Elbette bu hayallerimizin sonu değil. Ayrıca ücretsiz bir dilbilgisi uygulamak için mevcut kitaplıklardan herhangi birini kullanarak gorp şablon ayrıştırıcısını C#'ta tamamen yeniden yazabilirsiniz. Kodun önemli ölçüde basitleştirilmesi gerektiğini düşünüyorum ve bu, mevcut Java kaynakları biçimindeki mirastan kurtulmamıza olanak tanıyacak. Ancak mevcut motor türüyle, çeşitli web sitelerinden çeşitli verilerin ayrıştırılmasının yanı sıra, daha önce bahsettiğim meta şablonları uygulama girişimi de dahil olmak üzere çeşitli ilginç şeyler yapmak da oldukça mümkündür (ancak, bunu göz ardı etmiyorum) mevcut özel yazılım araçlarının bunun için daha uygun olduğunu düşünüyorum – henüz bunları kullanma konusunda uygun deneyimim olmadı).

Bu arada, bu yaz Salesforce teknolojilerini kullanan bir şirketten (orijinal oyunun geliştiricisi) e-posta yoluyla bir davetiye aldım. gorp), Riga'da daha sonraki çalışmalar için bir röportaj yapın. Maalesef şu anda bu tür yeniden görevlendirmelere hazır değilim.

Bu materyal biraz ilgi uyandırırsa, ikinci bölümde Salesforce'ta kullanılan uygulama örneğini kullanarak şablonları derleme ve ardından ayrıştırma teknolojisini daha ayrıntılı olarak açıklamaya çalışacağım. gorp (kendi eklemelerim, daha önce açıklanan birkaç işlev sözcüğü dışında, şablonun sözdiziminde hemen hemen hiçbir değişiklik yapmaz, dolayısıyla orijinal sistemin neredeyse tüm belgeleri gorp Benim versiyonuma da uygun).

Kaynak: habr.com

Yorum ekle