Мне интересно, как я могу идентифицировать заголовки с разными стилями числовой маркировки с помощью одного или нескольких регулярных выражений, предполагая, что иногда стили перекрываются между документами.Цель состоит в том, чтобы извлечь все подзаголовки и данные для определенного заголовка в каждом файле, но эти файлы не стандартизированы.Регулярные выражения - даже правильный подход?
Я работаю над программой, которая анализирует файл .pdf и ищет определенный раздел.Как только он находит раздел, он находит все подразделы этого раздела и их содержание и сохраняет его в dictionary<string, string>
.Я начинаю с чтения всего pdf в строку, а затем использую эту функцию, чтобы найти раздел «маркировка».
private string GetMarkingSection(string text)
{
int startIndex = 0;
int endIndex = 0;
bool startIndexFound = false;
Regex rx = new Regex(HEADINGREGEX);
foreach (Match match in rx.Matches(text))
{
if (startIndexFound)
{
endIndex = match.Index;
break;
}
if (match.ToString().ToLower().Contains("marking"))
{
startIndex = match.Index;
startIndexFound = true;
}
}
return text.Substring(startIndex, (endIndex - startIndex));
}
После того, как раздел маркировки найден, я использую его для поиска подразделов.
private Dictionary<string, string> GetSubsections(string text)
{
Dictionary<string, string> subsections = new Dictionary<string, string>();
string[] unprocessedSubSecs = Regex.Split(text, SUBSECTIONREGEX);
string title = "";
string content = "";
foreach(string s in unprocessedSubSecs)
{
if(s != "") //sometimes it pulls in empty strings
{
Match m = Regex.Match(s, SUBSECTIONREGEX);
if (m.Success)
{
title = s;
}
else
{
content = s;
if (!String.IsNullOrWhiteSpace(content) && !String.IsNullOrWhiteSpace(title))
{
subsections.Add(title, content);
}
}
}
}
return subsections;
}
Получение этих методов для работы так, как я хочу, не является проблемой, проблема в том, чтобы заставить их работать с каждым из документов. Я работаю над коммерческим приложением, поэтому любой API, для которого требуется лицензия, не будет работать для меня. Этим документам где-то от 1 до 16 лет, поэтому форматирование довольно сильно различается. Вот ссылка на некоторые примеры заголовков и подзаголовков из различных документов. Но, чтобы упростить задачу, я использую шаблоны регулярных выражений:
- Заголовок:
(?m)^(\d+\.\d+\s[ \w,\-]+)\r?$
- Подзаголовок:
(?m)^(\d\.[\d.]+ ?[ \w]+) ?\r?$
- Мастер-ключ:
(?m)^(\d\.?[\d.]*? ?[ \-,:\w]+) ?\r?$
Поскольку некоторые заголовки используют формат подзаголовка в других документах, я не могу использовать этот заголовокрегулярное выражение для каждого файла, и то же самое относится к моему регулярному выражению подзаголовка.
Моя альтернатива этому заключалась в том, что я собирался написать мастер-ключ (указанный в ссылке на регулярное выражение), чтобы идентифицировать все типы заголовков, а затем найтипоследний экземпляр числового символа в каждом заголовке (5.1.X), а затем найдите 5.1.X + 1, чтобы найти конец этого раздела.
Вот тогда я столкнулся с другой проблемой.Некоторые из этих файлов не имеют абсолютно правильной структуры.Большинство из них выходят из 5.2-> 7.1.5 (ожидается 5.2-> 5.3 / 6.0)
Я пытаюсь обернуть голову вокруг решения для чего-то подобного, но у меня ничего нет... Я открыт для идей, не связанных с регулярными выражениями.
Вот мой обновленный метод GetMarkingSection
:
private Dictionary<string, string> GetMarkingSection(string text)
{
var headingRegex = HEADING1REGEX;
var subheadingRegex = HEADING2REGEX;
Dictionary<string, string> markingSection = new Dictionary<string, string>();
if (Regex.Matches(text, HEADING1REGEX, RegexOptions.Multiline | RegexOptions.Singleline).Count > 0)
{
foreach (Match m in Regex.Matches(text, headingRegex, RegexOptions.Multiline | RegexOptions.Singleline))
{
if (Regex.IsMatch(m.ToString(), HEADINGMASTERKEY))
{
if (m.Groups[2].Value.ToLower().Contains("marking"))
{
var subheadings = Regex.Matches(m.ToString(), subheadingRegex, RegexOptions.Multiline | RegexOptions.Singleline);
foreach (Match s in subheadings)
{
markingSection.Add(s.Groups[1].Value + " " + s.Groups[2].Value, s.Groups[3].Value);
}
return markingSection;
}
}
}
}
else
{
headingRegex = HEADING2REGEX;
subheadingRegex = HEADING3REGEX;
foreach(Match m in Regex.Matches(text, headingRegex, RegexOptions.Multiline | RegexOptions.Singleline))
{
if(Regex.IsMatch(m.ToString(), HEADINGMASTERKEY))
{
if (m.Groups[2].Value.ToLower().Contains("marking"))
{
var subheadings = Regex.Matches(m.ToString(), subheadingRegex, RegexOptions.Multiline | RegexOptions.Singleline);
foreach (Match s in subheadings)
{
markingSection.Add(s.Groups[1].Value + " " + s.Groups[2].Value, s.Groups[3].Value);
}
return markingSection;
}
}
}
}
return null;
}
Вот несколько примеров файлов PDF:
![Style 2](https://i.stack.imgur.com/z1ApI.png)