用正则表达式识别标题

时间:2018-06-08 20:35:25

标签: c# regex parsing pdf

我想知道如何使用一个或多个正则表达式识别具有不同数字标记样式的标题,假设文档之间有时样式重叠。目标是提取每个文件中特定标题的所有子标题和数据,但这些文件没有标准化。正则表达式甚至是正确的方法吗?

我正在开发一个解析.pdf文件并查找特定部分的程序。找到该部分后,它会找到该部分的所有子部分及其内容,并将其存储在dictionary<string, string>中。我首先将整个pdf读入一个字符串,然后使用此函数找到&#34;标记&#34;部分。

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岁不等,因此格式有所不同。 Here is a link to some sample headings and subheadings from various documents.但为了简单起见,以下是我使用的正则表达式模式:

  • 标题:(?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 1 Style 2

1 个答案:

答案 0 :(得分:1)

看看这种方法是否有效:

```{r results='asis', echo=FALSE}
#basic table
  library(knitr)
  library(kableExtra)
  x1 <- rnorm(100,0,1)
  x2 <- rpois(100,5)
  y1 <- rbinom(100,1,0.33)
  df <- data.frame(x1,x2,y1)
  modelx <- glm(y1 ~ x1 + x2, data = df ,family = "binomial")
  tableit <- data.frame(summary(modelx)$coef)
  tableit$OR <- exp(tableit$Estimate)
  tableit$LCL <- exp(tableit$Estimate - tableit$Std..Error * 1.96 )
  tableit$UCL <- exp(tableit$Estimate + tableit$Std..Error * 1.96 )
  tableit$`p-value` <- tableit$Pr...z..
  tableit <- tableit[c(5,6,7,8)]
  kable(tableit, digits = 2, align = rep('c',4 )) %>%
    kable_styling(bootstrap_options = "striped", full_width = F)
```

Demo

var heading1Regex = @"^(\d+)\s(?<title>.*?)$\n(?<content>.*?)$\n*(?=^\d+\s|\Z)";

Demo

var heading2Regex = @"^(\d+)\.(\d+)\s(?<title>.*?)$\n(?<content>.*?)$\n*(?=^\d+\.\d+\s|\Z)";

Demo

对于每个pdf文件:

var heading3Regex = @"^(\d+)\.(\d+)\.(\d+)\s(?<title>.*?)$\n(?<content>.*?)$\n*(?=^\d+\.\d+\.\d+\s|\Z)";

<强> 1。边缘情况1:在5.2之后,来到7.1.3

如图所示here, 使用heading2Regex获取主要部分匹配。

将匹配的group1转换为整数

var headingRegex = heading1Regex;
var subHeadingRegex = heading2Regex;

if there are any matches for headingRegex
{
    for each match, find matches for subHeadingRegex
}
else
{
    var headingRegex = heading2Regex;
    var subHeadingRegex = heading3Regex;
    //repeat same steps
}

获取heading3Regex的子节匹配

对于每个子部分匹配,将group1转换为整数。

int.TryParse(match.group1, out var headingIndex);

检查headingIndex是否等于subHeadingIndex。如果没有相应的处理。