Câu chuyện về một dự án nhỏ kéo dài mười hai năm (về BIRMA.NET lần đầu tiên và thẳng thắn trực tiếp)

Sự ra đời của dự án này có thể được coi là một ý tưởng nhỏ đến với tôi vào khoảng cuối năm 2007, ý tưởng này đã được định sẵn chỉ 12 năm sau mới tìm được hình thức cuối cùng (tại thời điểm này - tất nhiên, mặc dù việc triển khai hiện tại, theo đối với tác giả là rất hài lòng).

Mọi chuyện bắt đầu khi, trong quá trình hoàn thành nhiệm vụ chính thức lúc bấy giờ của mình trong thư viện, tôi đã chú ý đến thực tế là quá trình nhập dữ liệu từ văn bản được quét của mục lục các ấn phẩm sách (và âm nhạc) vào cơ sở dữ liệu hiện có, rõ ràng, có thể được đơn giản hóa và tự động hóa đáng kể, tận dụng đặc tính về tính trật tự và tính lặp lại của tất cả dữ liệu cần thiết cho đầu vào, chẳng hạn như tên tác giả của bài báo (nếu chúng ta đang nói về một tập hợp các bài báo), tiêu đề của bài viết (hoặc phụ đề phản ánh trong mục lục) và số trang của mục mục lục hiện tại. Lúc đầu, tôi gần như bị thuyết phục rằng có thể dễ dàng tìm thấy một hệ thống phù hợp để thực hiện nhiệm vụ này trên Internet. Khi có điều bất ngờ xảy ra do tôi không thể tìm được một dự án như vậy, tôi quyết định thử tự mình thực hiện nó.

Sau một thời gian khá ngắn, nguyên mẫu đầu tiên bắt đầu hoạt động và tôi ngay lập tức bắt đầu sử dụng nguyên mẫu này trong các hoạt động hàng ngày của mình, đồng thời gỡ lỗi trên tất cả các ví dụ có trong tay tôi. May mắn thay, tại nơi làm việc quen thuộc của tôi, nơi tôi hoàn toàn không phải là một lập trình viên, tôi vẫn thoát khỏi “thời gian chết” rõ ràng trong công việc của mình, trong thời gian đó tôi đang miệt mài gỡ lỗi cho đứa con tinh thần của mình - một điều gần như không thể tưởng tượng được trong thực tế hiện tại, điều đó ngụ ý báo cáo hàng ngày về công việc thực hiện trong ngày. Quá trình hoàn thiện chương trình mất tổng cộng không dưới một năm, nhưng ngay cả sau đó, kết quả cũng khó có thể được gọi là thành công hoàn toàn - có quá nhiều khái niệm khác nhau được đặt ra ban đầu mà không hoàn toàn rõ ràng để thực hiện: các yếu tố tùy chọn có thể được bỏ qua; xem trước các phần tử (với mục đích thay thế các phần tử trước đó vào kết quả tìm kiếm); thậm chí cả nỗ lực của chúng tôi để triển khai một cái gì đó như biểu thức chính quy (có cú pháp duy nhất). Tôi phải nói rằng trước đó tôi đã từ bỏ việc lập trình một phần (khoảng 8 năm, nếu không muốn nói là hơn), vì vậy cơ hội mới để áp dụng các kỹ năng của mình vào một nhiệm vụ thú vị và cần thiết đã hoàn toàn thu hút sự chú ý của tôi. Không có gì đáng ngạc nhiên khi mã nguồn thu được - do tôi không có bất kỳ cách tiếp cận rõ ràng nào đối với thiết kế của nó - khá nhanh chóng trở thành một mớ hỗn độn không thể tưởng tượng được của các phần khác nhau trong ngôn ngữ C với một số thành phần của C++ và các khía cạnh của lập trình trực quan (ban đầu nó đã quyết định sử dụng hệ thống thiết kế như Borland C++ Builder - “gần như Delphi, nhưng ở C”). Tuy nhiên, tất cả những điều này cuối cùng đã mang lại kết quả trong việc tự động hóa các hoạt động hàng ngày của thư viện của chúng tôi.

Đồng thời, tôi quyết định tham gia các khóa đào tạo các nhà phát triển phần mềm chuyên nghiệp để đề phòng. Tôi không biết liệu có thực sự có thể học “trở thành lập trình viên” từ đầu ở đó hay không, nhưng dựa trên những kỹ năng tôi đã có vào thời điểm đó, tôi có thể phần nào nắm vững các công nghệ phù hợp hơn vào thời điểm đó, chẳng hạn như như C#, Visual Studio để phát triển trên .NET, cũng như một số công nghệ liên quan đến Java, HTML và SQL. Toàn bộ quá trình đào tạo kéo dài tổng cộng hai năm và là điểm khởi đầu cho một dự án khác của tôi, dự án này cuối cùng kéo dài trong vài năm - nhưng đây là chủ đề cho một ấn phẩm riêng. Ở đây chỉ cần lưu ý rằng tôi đã cố gắng điều chỉnh những phát triển mà tôi đã có trong dự án được mô tả để tạo ra một ứng dụng cửa sổ chính thức trong C# và WinForms thực hiện các chức năng cần thiết và sử dụng nó làm cơ sở cho đồ án tốt nghiệp sắp tới.
Theo thời gian, đối với tôi, ý tưởng này bắt đầu xứng đáng được nêu tại các hội nghị thường niên với sự tham gia của đại diện các thư viện khác nhau như “LIBKOM” và “CRIMEA”. Ý tưởng thì có, nhưng tôi chưa thực hiện nó vào thời điểm đó. Sau đó, tôi cũng hy vọng rằng ai đó sẽ viết lại nó bằng những cách tiếp cận hiệu quả hơn. Bằng cách này hay cách khác, đến năm 2013 tôi quyết định viết báo cáo sơ bộ về công việc của mình và gửi đến Ban tổ chức Hội nghị kèm theo đơn xin tài trợ để tham gia hội nghị. Tôi hơi ngạc nhiên khi đơn đăng ký của tôi đã được chấp thuận và tôi bắt đầu thực hiện một số cải tiến cho dự án để chuẩn bị trình bày tại hội nghị.

Vào thời điểm đó, dự án đã nhận được tên mới BIRMA, có được nhiều khả năng bổ sung khác nhau (không được triển khai đầy đủ nhưng chỉ là giả định) - tất cả các chi tiết có thể được tìm thấy trong báo cáo của tôi.

Thành thật mà nói, thật khó để gọi BIRMA 2013 là một cái gì đó trọn vẹn; Thành thật mà nói, đó là một công việc rất khó khăn được thực hiện một cách vội vàng. Về mặt mã, thực tế không có cải tiến đặc biệt nào cả, ngoại trừ một nỗ lực khá bất lực nhằm tạo ra một loại cú pháp thống nhất nào đó cho trình phân tích cú pháp, có vẻ ngoài gợi nhớ đến ngôn ngữ định dạng IRBIS 64 (và trên thực tế, cả hệ thống ISIS - với dấu ngoặc đơn là cấu trúc tuần hoàn; tại sao Lúc đó tôi nghĩ nó trông khá tuyệt). Trình phân tích cú pháp vô tình vấp phải các vòng tròn dấu ngoặc đơn thuộc loại thích hợp này (vì dấu ngoặc đơn cũng thực hiện một vai trò khác, cụ thể là chúng đánh dấu các cấu trúc tùy chọn trong quá trình phân tích cú pháp có thể được bỏ qua). Một lần nữa, tôi giới thiệu chi tiết hơn với tất cả những ai muốn làm quen với cú pháp khó tưởng tượng và phi lý của BIRMA trong báo cáo của tôi vào thời điểm đó.

Nói chung, ngoài việc vật lộn với trình phân tích cú pháp của riêng mình, tôi không còn gì để nói về mã của phiên bản này - ngoại trừ việc chuyển đổi ngược các nguồn hiện có thành C++ trong khi vẫn giữ được một số tính năng điển hình của mã .NET (thành thật mà nói, đó là khó hiểu, chính xác thì điều gì đã thúc đẩy tôi chuyển mọi thứ trở lại - có lẽ là nỗi sợ hãi ngu ngốc nào đó khi giữ bí mật mã nguồn của tôi, như thể nó là thứ gì đó tương đương với công thức bí mật của Coca-Cola).

Có lẽ quyết định ngu ngốc này cũng là nguyên nhân gây ra những khó khăn trong việc ghép nối thư viện DLL thu được với giao diện hiện có của máy trạm tự chế để nhập dữ liệu vào danh mục điện tử (vâng, tôi không đề cập đến một thực tế quan trọng khác: kể từ bây giờ, tất cả mã của “công cụ” BIRMA đúng như mong đợi, nó được tách ra khỏi phần giao diện và được đóng gói trong DLL thích hợp). Tại sao cần phải viết một máy trạm riêng cho những mục đích này, mà dù sao, về hình thức và phương thức tương tác với người dùng, đã sao chép một cách trơ tráo cùng một máy trạm “Catalogizer” của hệ thống IRBIS 64 - đây là một câu hỏi riêng. Nói tóm lại: nó mang lại sự vững chắc cần thiết cho sự phát triển sau đó của tôi cho đồ án tốt nghiệp của tôi (nếu không thì chỉ riêng công cụ phân tích cú pháp khó tiêu thôi là chưa đủ). Ngoài ra, sau đó tôi gặp phải một số khó khăn trong việc triển khai giao diện của máy trạm Cataloger với các mô-đun của riêng tôi, được triển khai trong cả C++ và C# và truy cập trực tiếp vào công cụ của tôi.

Nói chung, thật kỳ lạ, chính nguyên mẫu khá vụng về này của BIRMA.NET trong tương lai lại được định sẵn trở thành “con ngựa thồ” của tôi trong bốn năm tới. Không thể nói rằng trong thời gian này tôi đã không ít nhất cố gắng tìm cách thực hiện mới, hoàn thiện hơn một ý tưởng lâu đời. Trong số những đổi mới khác, lẽ ra phải có các chuỗi tuần hoàn lồng nhau có thể bao gồm các phần tử tùy chọn - đây là cách tôi định hiện thực hóa ý tưởng về các mẫu phổ quát dành cho mô tả thư mục của các ấn phẩm và nhiều điều thú vị khác. Tuy nhiên, trong hoạt động thực tế của tôi vào thời điểm đó, tất cả những điều này ít có nhu cầu và cách thực hiện của tôi lúc đó là khá đủ để nhập mục lục. Ngoài ra, xu hướng phát triển thư viện của chúng tôi bắt đầu ngày càng đi chệch hướng theo hướng số hóa các kho lưu trữ bảo tàng, báo cáo và các hoạt động khác mà tôi ít quan tâm, điều này cuối cùng buộc tôi phải rời bỏ nó, nhường chỗ cho những người sẽ hài lòng hơn với tất cả điều này.

Nghịch lý thay, chính sau những sự kiện kịch tính này, dự án BIRMA, lúc đó vốn đã có đầy đủ những nét đặc trưng của một dự án xây dựng dài hạn điển hình, lại dường như bắt đầu bước vào cuộc sống mới đã được chờ đợi từ lâu! Tôi có nhiều thời gian rảnh hơn cho những suy nghĩ vu vơ, tôi lại bắt đầu lùng sục World Wide Web để tìm kiếm thứ gì đó tương tự (may mắn thay, bây giờ tôi đã có thể đoán rằng sẽ tìm kiếm tất cả những thứ này không chỉ ở bất cứ đâu mà là trên GitHub), và ở đâu đó trong At the Đầu năm nay, cuối cùng tôi cũng tìm được một sản phẩm tương ứng của công ty Salesforce nổi tiếng với cái tên tầm thường gop. Bản thân nó có thể thực hiện hầu hết mọi thứ tôi cần từ một công cụ phân tích cú pháp như vậy - cụ thể là tách biệt một cách thông minh các đoạn riêng lẻ khỏi văn bản tùy ý nhưng có cấu trúc rõ ràng, đồng thời có giao diện khá thân thiện với người dùng cho người dùng cuối, bao gồm cả những bản chất dễ hiểu như vậy, như một mẫu, khuôn mẫu và sự xuất hiện, đồng thời sử dụng cú pháp quen thuộc của các biểu thức chính quy, trở nên dễ đọc hơn rất nhiều nhờ sự phân chia thành các nhóm ngữ nghĩa được chỉ định để phân tích cú pháp.

Nói chung, tôi quyết định rằng đây là một gop (Tôi tự hỏi cái tên này có nghĩa là gì? Có lẽ là một loại “trình phân tích cú pháp thông thường có định hướng chung”?) - chính xác là thứ mà tôi đã tìm kiếm bấy lâu nay. Đúng vậy, việc triển khai ngay lập tức nó cho nhu cầu của tôi đã gặp phải một vấn đề là công cụ này yêu cầu tuân thủ quá nghiêm ngặt trình tự cấu trúc của văn bản nguồn. Đối với một số báo cáo như tệp nhật ký (cụ thể là chúng được các nhà phát triển đặt làm ví dụ rõ ràng về việc sử dụng dự án), điều này khá phù hợp, nhưng đối với cùng một văn bản của các mục lục được quét thì điều đó khó xảy ra. Rốt cuộc, cùng một trang có mục lục có thể bắt đầu bằng các từ “Mục lục”, “Nội dung” và bất kỳ mô tả sơ bộ nào khác mà chúng tôi không cần đưa vào kết quả phân tích dự định (và cắt chúng theo cách thủ công). lần nào cũng bất tiện). Ngoài ra, giữa các phần tử lặp lại riêng lẻ, chẳng hạn như tên tác giả, tiêu đề và số trang, trang có thể chứa một lượng rác nhất định (ví dụ: hình vẽ và chỉ các ký tự ngẫu nhiên), điều này cũng sẽ rất tuyệt nếu có thể cắt. Tuy nhiên, khía cạnh cuối cùng vẫn chưa quá quan trọng, nhưng do khía cạnh đầu tiên, việc triển khai hiện tại không thể bắt đầu tìm kiếm các cấu trúc cần thiết trong văn bản từ một vị trí nhất định mà thay vào đó chỉ xử lý nó ngay từ đầu, không tìm thấy các mẫu được chỉ định ở đó và... kết thúc công việc của tôi. Rõ ràng, cần phải có một số điều chỉnh để ít nhất có khoảng trống giữa các cấu trúc lặp lại và điều đó đã giúp tôi quay lại làm việc.

Một vấn đề khác là bản thân dự án đã được triển khai bằng Java và nếu trong tương lai tôi dự định triển khai một số phương tiện kết nối công nghệ này với các ứng dụng quen thuộc để nhập dữ liệu vào cơ sở dữ liệu hiện có (chẳng hạn như “Cataloger” của Irbis), thì ít nhất Ít nhất làm điều này trong C# và .NET. Bản thân Java không phải là ngôn ngữ xấu - tôi thậm chí còn từng sử dụng nó để triển khai một ứng dụng cửa sổ thú vị triển khai chức năng của một máy tính lập trình trong nước (như một phần của dự án khóa học). Và về mặt cú pháp, nó rất giống với chữ C giống nhau. Chà, đây chỉ là một điểm cộng: tôi càng dễ dàng hoàn thành một dự án hiện có hơn. Tuy nhiên, tôi không muốn lao vào thế giới công nghệ Java cửa sổ (hay đúng hơn là máy tính để bàn) khá bất thường này - xét cho cùng, bản thân ngôn ngữ này không được “điều chỉnh” cho mục đích sử dụng như vậy và tôi hoàn toàn không khao khát sự lặp lại của kinh nghiệm trước đó. Có lẽ chính xác là vì C# kết hợp với WinForms gần với Delphi hơn nhiều, điều mà nhiều người trong chúng ta đã từng bắt đầu. May mắn thay, giải pháp cần thiết đã được tìm ra khá nhanh chóng - dưới dạng dự án IKVM.NET, giúp dễ dàng dịch các chương trình Java hiện có sang mã .NET được quản lý. Đúng, bản thân dự án đã bị các tác giả bỏ rơi vào thời điểm đó, nhưng việc triển khai mới nhất của nó đã cho phép tôi thực hiện khá thành công các hành động cần thiết đối với văn bản nguồn gop.

Vì vậy, tôi đã thực hiện tất cả những thay đổi cần thiết và tập hợp tất cả thành một DLL thuộc loại thích hợp, có thể dễ dàng được “chọn lọc” bởi bất kỳ dự án nào dành cho .NET Framework được tạo trong Visual Studio. Trong thời gian chờ đợi, tôi tạo một lớp khác để thuận tiện cho việc trình bày kết quả trả về gop, dưới dạng cấu trúc dữ liệu tương ứng sẽ thuận tiện để xử lý trong chế độ xem bảng (lấy cả hàng và cột làm cơ sở; cả khóa từ điển và chỉ mục số). Chà, bản thân các tiện ích cần thiết để xử lý và hiển thị kết quả đã được viết khá nhanh.

Ngoài ra, quá trình điều chỉnh các mẫu cho công cụ mới để dạy nó phân tích các mẫu văn bản được quét hiện có của mục lục không gây ra bất kỳ sự phức tạp đặc biệt nào. Trên thực tế, tôi thậm chí còn không cần phải tham khảo các mẫu trước đó của mình: tôi chỉ cần tạo tất cả các mẫu cần thiết từ đầu. Hơn nữa, nếu các mẫu được thiết kế để hoạt động với phiên bản trước của hệ thống đặt ra một khuôn khổ khá hẹp cho các văn bản có thể được phân tích cú pháp chính xác với sự trợ giúp của chúng, thì công cụ mới đã có thể phát triển các mẫu khá phổ biến phù hợp với một số loại đánh dấu tại một lần. Tôi thậm chí đã cố gắng viết một số loại mẫu toàn diện cho bất kỳ văn bản mục lục tùy ý nào, mặc dù, tất nhiên, ngay cả với tất cả các khả năng mới mở ra cho tôi, đặc biệt là khả năng hạn chế để thực hiện cùng một chuỗi lặp lại lồng nhau ( chẳng hạn như họ và tên viết tắt của một số tác giả liên tiếp), điều này hóa ra là một điều không tưởng.

Có lẽ trong tương lai sẽ có thể triển khai một khái niệm nhất định về siêu mẫu, có thể kiểm tra văn bản nguồn xem có tuân thủ một số mẫu có sẵn cùng một lúc hay không, sau đó, theo kết quả thu được, hãy chọn phù hợp nhất, sử dụng một số loại thuật toán thông minh. Nhưng bây giờ tôi quan tâm hơn đến một câu hỏi khác. Một trình phân tích cú pháp như gop, bất chấp tất cả tính linh hoạt và những sửa đổi mà tôi đã thực hiện, nó vẫn không có khả năng thực hiện một việc có vẻ đơn giản mà trình phân tích cú pháp tự viết của tôi có thể thực hiện ngay từ phiên bản đầu tiên. Cụ thể: anh ta có khả năng tìm và trích xuất từ ​​văn bản nguồn tất cả các đoạn khớp với mặt nạ được chỉ định trong mẫu được sử dụng ở đúng vị trí, trong khi không hề quan tâm đến nội dung văn bản đã cho trong khoảng trắng giữa các đoạn này. Cho đến nay, tôi chỉ cải tiến một chút công cụ mới, cho phép nó tìm kiếm tất cả các lần lặp lại mới có thể có của một chuỗi các mặt nạ như vậy từ vị trí hiện tại, để lại khả năng xuất hiện trong văn bản các tập hợp ký tự tùy ý hoàn toàn không được tính đến trong quá trình phân tích cú pháp, được đặt giữa các cấu trúc lặp lại được phát hiện. Tuy nhiên, điều này không cho phép đặt mặt nạ tiếp theo bất kể kết quả tìm kiếm đoạn trước bằng mặt nạ tương ứng: tính nghiêm ngặt của cấu trúc văn bản được mô tả vẫn không có chỗ cho việc đưa vào tùy ý các ký tự không đều.

Và nếu đối với các ví dụ về mục lục mà tôi gặp phải, vấn đề này có vẻ chưa quá nghiêm trọng, thì khi cố gắng áp dụng một cơ chế phân tích cú pháp mới cho một nhiệm vụ tương tự là phân tích nội dung của một trang web (tức là cùng một phân tích cú pháp), thì đó là những hạn chế ở đây chúng đã xuất hiện với tất cả sự rõ ràng của chúng. Rốt cuộc, khá dễ dàng để đặt các mặt nạ cần thiết cho các đoạn đánh dấu web, giữa đó phải đặt dữ liệu chúng ta đang tìm kiếm (cần trích xuất), nhưng làm cách nào chúng ta có thể buộc trình phân tích cú pháp chuyển ngay sang phần tiếp theo đoạn tương tự, bất chấp tất cả các thẻ và thuộc tính HTML có thể được đặt trong khoảng trắng giữa chúng?

Sau khi suy nghĩ một chút, tôi quyết định giới thiệu một vài mẫu dịch vụ (%all_trước) и (%all_after), phục vụ mục đích rõ ràng là đảm bảo rằng mọi thứ có thể chứa trong văn bản nguồn đều bị bỏ qua trước bất kỳ mẫu (mặt nạ) nào theo sau chúng. Hơn nữa, nếu (%all_trước) chỉ đơn giản là bỏ qua tất cả những sự bao gồm tùy ý này, sau đó (%all_after)ngược lại, cho phép chúng được thêm vào đoạn mong muốn sau khi di chuyển từ đoạn trước đó. Nghe có vẻ khá đơn giản, nhưng để triển khai khái niệm này, tôi đã phải xem xét lại các nguồn gorp để thực hiện các sửa đổi cần thiết để không phá vỡ logic đã được triển khai. Cuối cùng, chúng tôi đã làm được điều này (mặc dù ngay cả lần đầu tiên, mặc dù rất có lỗi, việc triển khai trình phân tích cú pháp của tôi đã được viết và thậm chí còn nhanh hơn - trong một vài tuần). Kể từ bây giờ, hệ thống đã mang một hình thức thực sự phổ biến - không dưới 12 năm sau những nỗ lực đầu tiên để nó hoạt động.

Tất nhiên, đây không phải là kết thúc giấc mơ của chúng tôi. Bạn cũng có thể viết lại hoàn toàn trình phân tích cú pháp mẫu gorp trong C#, sử dụng bất kỳ thư viện có sẵn nào để triển khai ngữ pháp miễn phí. Tôi nghĩ mã nên được đơn giản hóa đáng kể và điều này sẽ cho phép chúng tôi loại bỏ di sản ở dạng các nguồn Java hiện có. Nhưng với loại công cụ hiện có, bạn cũng có thể thực hiện nhiều điều thú vị khác nhau, bao gồm nỗ lực triển khai các siêu mẫu mà tôi đã đề cập, chưa kể đến việc phân tích cú pháp nhiều dữ liệu khác nhau từ các trang web khác nhau (tuy nhiên, tôi không loại trừ rằng các công cụ phần mềm chuyên dụng hiện có phù hợp hơn cho việc này - chỉ là tôi chưa có kinh nghiệm thích hợp để sử dụng chúng).

Nhân tiện, mùa hè này tôi đã nhận được lời mời qua email từ một công ty sử dụng công nghệ Salesforce (nhà phát triển ứng dụng gốc gop), vượt qua một cuộc phỏng vấn cho công việc tiếp theo ở Riga. Thật không may, hiện tại tôi chưa sẵn sàng cho việc tái triển khai như vậy.

Nếu tài liệu này khơi dậy một số sự quan tâm, thì trong phần thứ hai, tôi sẽ cố gắng mô tả chi tiết hơn về công nghệ biên dịch và phân tích cú pháp các mẫu sau đó bằng cách sử dụng ví dụ về cách triển khai được sử dụng trong Salesforce gop (các phần bổ sung của riêng tôi, ngoại trừ một số từ chức năng đã được mô tả, hầu như không tạo ra thay đổi nào đối với chính cú pháp mẫu, vì vậy hầu như tất cả tài liệu cho hệ thống gốc đều gop Thích hợp cho phiên bản của tôi quá).

Nguồn: www.habr.com

Thêm một lời nhận xét