💡 Повний робочий приклад доступний на GitHub:
parse-docx-to-markdown-chunks-dotnet
Старий спосіб був болючим
Розбиття Markdown за заголовками — це .NET підготовчий шлях, який перетворює файли Office та PDF у текст розміром з розділ перед вбудовуванням. Без цього команди часто завантажують увесь файл Word в один вектор. Абзац обкладинки та пункт обов’язків ділять одне вбудовування, тому пошук за косинусом ранжує неправильний розділ. Я зіткнувся з цим у трьохсторінковому внутрішньому посібнику: кожен запит спочатку витягав блок заголовка, бо індекс ніколи не бачив структуру # / ##, яку вже написали автори.
Самостійна розробка конвертера DOCX у Markdown означає проходження стилів Open XML, відображення рівнів списків і все ще помилки, коли наступне завантаження — PDF, у якого шлях форматованого Markdown повертає null. Вікна токенів фіксованого розміру ігнорують ці заголовки. За ніч корпуси змішують порожні оболонки з величезними посібниками, бо ніхто спочатку не перевіряє кількість сторінок чи розмір.
Справжня вартість вбудовувань цілого файлу: відповіді з неправильними розділами, витрачений на зайві витяги час на небажані завантаження та відсутність артефактів
chunk-01.md, які оператори могли б відкрити під час поганої партії.
Є кращий спосіб
GroupDocs.Parser для .NET замінює цей безлад чотирма цілеспрямованими викликами: GetDocumentInfo, GetFormattedText(FormattedTextMode.Markdown), GetText, коли Markdown дорівнює null, та невеликий обхід заголовків, який записує chunk-NN.md. Той самий тип Parser охоплює розбір Word DOCX та резервний текст PDF, тому ви зберігаєте один шлях сервісу C#.
Вам знадобиться:
- .NET 8 SDK
- GroupDocs.Parser 26.10.0 (temporary license)
- DOCX Word (зразок має 3 сторінки / 14820 байт) та за бажанням PDF
dotnet add package GroupDocs.Parser --version 26.10.0
Новий спосіб: інспектувати, витягувати, резервний варіант, розділяти
Ось та сама підготовка отримання після переходу. Консольний приклад у parse-docx-to-markdown-chunks-dotnet записує інформацію, Markdown, текст PDF та чотири частини заголовків для постаченого DOCX.
Крок 1 — Перевірка за допомогою GetDocumentInfo
Запитайте тип файлу, кількість сторінок та розмір перед тим, як платити за повний витяг.
using var parser = new Parser(sourcePath);
var info = parser.GetDocumentInfo();
var sb = new StringBuilder();
sb.AppendLine($"Source: {Path.GetFileName(sourcePath)}");
sb.AppendLine($"File type: {info?.FileType}");
sb.AppendLine($"Pages: {info?.PageCount}");
sb.AppendLine($"Size: {info?.Size} bytes");
File.WriteAllText(outputPath, sb.ToString());
Запишіть ці факти поруч з ідентифікатором завдання. У зразку DOCX ви повинні бачити Microsoft Word Open XML Document, 3 сторінки та 14820 байт.
Крок 2 — Надати перевагу Markdown з GetFormattedText
Для Word та форматів, які підтримують форматований витяг, зберігайте ATX‑заголовки для розділювача.
using var parser = new Parser(sourcePath);
using TextReader? reader = parser.GetFormattedText(
new FormattedTextOptions(FormattedTextMode.Markdown));
if (reader == null)
{
return null;
}
string markdown = reader.ReadToEnd();
File.WriteAllText(outputPath, markdown, Encoding.UTF8);
return markdown;
Null — це сигнал переключитися на інший шлях, а не збій. Записуйте у UTF-8, щоб інструменти розбиття та diff у git залишалися читабельними.
Крок 3 — Резервний варіант з GetText для PDF
Коли режим Markdown повертає null, залишайте файл у конвеєрі з простим текстовим шаром.
using var parser = new Parser(sourcePath);
using TextReader? reader = parser.GetText();
if (reader == null)
{
return null;
}
string text = reader.ReadToEnd();
File.WriteAllText(outputPath, text, Encoding.UTF8);
return text;
Очікуйте .txt, а не вигадані заголовки #. Приклад хосту записує Result/sample-pdf.txt для гілки PDF.
Крок 4 — Розбити Markdown за # та
Пройдіться по рядках; завершіть, коли з’явиться новий ATX # або ##; запишіть chunk-NN.md.
var chunks = new List<string>();
var current = new StringBuilder();
using (var reader = new StringReader(markdown))
{
string? line;
while ((line = reader.ReadLine()) != null)
{
bool isHeading = line.StartsWith("# ", StringComparison.Ordinal)
|| line.StartsWith("## ", StringComparison.Ordinal);
if (isHeading && current.Length > 0)
{
chunks.Add(current.ToString().TrimEnd());
current.Clear();
}
current.AppendLine(line);
}
}
Спочатку видаліть застарілі файли chunk-*.md. Глибші рядки ### залишаються всередині поточного розділу. Зразок DOCX створює чотири файли у Result/chunks/.
Коли слід замінити вбудовування цілого файлу цим шляхом?
Замінюйте вбудовування цілого файлу, коли вхід змішує Word DOCX та PDF, а індекс потребує Markdown розміром з розділ. Спочатку виконайте GetDocumentInfo, спробуйте Markdown для Office‑файлів, викличте GetText, коли форматований читач повертає null, і розбивайте лише коли існують маркери # / ##. Залиште неструктурований текст PDF без змін, доки не додасте окрему політику розбиття. Такий порядок відповідає прикладу консольного застосунку та робить режими помилок явними для операторів.
Що змінилося для операторів
| До | Після |
|---|---|
| Одне вбудовування на файл | Одне вбудовування на блок заголовка |
| Власний Open XML Markdown | GetFormattedText режим Markdown |
| PDF відкидається, коли форматований читач повертає null | GetText записує текстовий артефакт |
| Немає простого попереднього контролю | Працює перевірка кількості сторінок та розміру |
Вивільняйте кожен Parser та TextReader. Застосуйте ліцензію або temporary license перед нічним обсягом. Ставтеся до завантажень як до ненадійного вводу та парсуйте в ізольованому воркері.
Спробуйте це на власних файлах
Клонуйте parse-docx-to-markdown-chunks-dotnet, відновіть GroupDocs.Parser 26.10.0 та запустіть проти documents/sample.docx. Потім застосуйте ті ж чотири методи до одного зі своїх посібників і відкрийте згенеровані файли chunk-*.md.