是否可以使用正则表达式来提取不同的文本块和多行?

时间:2014-04-29 15:04:37

标签: c# regex

我想使用正则表达式从报表文档中提取不同的文本块 - 每个新页面在"第一通知"前面用\ x0c表示。 [未在下面显示]。虽然格式化可能是一个问题,但我已经包含了带行号和文本的图片。

报告文本将包含1..n页 - 每次返回数据时都是一个单独的行项。此数据将被提取并转换为行,以输入数据库[数字,余额,名称,地址1,地址2,城市,州,邮编]。

我需要提取的数据:

  1. NUMBER - 11-1-11111-1
  2. BALANCE - 1000.00
  3. 姓名 - " DOEN,JOHN THOMAS" [第14行,第7-50栏]
  4. 地址 - 2到3行
  5. 进一步 - 分为Addr1 / Addr2 / City / State / Zip
  6. 与城市的线路:城市ST Zip4或Zip-9
  7. 城市可以包含空格
  8. 数量和余额相对容易获得 - 它是我遇到最多问题的名称和地址部分,我正在寻找一个将每个项目拉到自己的组中的正则表达式。

    地址在第15-17行和第7-50行。

    这甚至可能吗?

    包含两个页面的示例文档:

    enter image description here

     FIRST NOTICE                         COMPANYNAME
     NOTICE DATE....: 01/01/2001          1111 N NORTHWOOD DR
     NUMBER.........: 11-1-11111-1        SOMEWHERE WY 05920-5929
     THE DATE.......: 02/01/2001
    
     Some data only.
    
    
    
    
    
    
    
          DOEN, JOHN THOMAS                           ORIGINAL....:      5789.00
          1111 N WALT AVE                             BALANCE.....:      1000.00
          C/O SOMEONE ELSE                            PAST DUE....:       500.00
          SOMEWHERE WY 04741-5555
    
     THIS IS THE END OF THIS PAGE                     DATE DUE: 02/01/2001
     FIRST NOTICE                         COMPANYNAME
     NOTICE DATE....: 01/01/2001          1111 N NORTHWOOD DR
     NUMBER.........: 22-2-22222-2        SOMEWHERE WY 05920-5929
     THE DATE.......: 02/01/2001
    
     Some data only.
    
    
    
    
    
    
    
          DOE, JOHNAT ZOAR                            ORIGINAL....:      2211.00
          11111 N DIVISOR RD                          BALANCE.....:      2000.00
          SOMWEHERE WY 05922                          PAST DUE....:      1000.00
    
    
     THIS IS THE END OF THIS PAGE                     DATE DUE: 02/01/2001
    

1 个答案:

答案 0 :(得分:2)

正则表达式明确支持多行,如下所示

Regex reg = new Regex(@"pattern1|pattern2", RegexOptions.Multiline);
var matches = reg.Matches("my text with /n lines");

正则表达式的另一个方面是,您可以将模式划分为多个段,这些段相当于要匹配的备用文本。请参阅vertical bar上的这篇文章。使用reg.Matches返回的MatchCollection,您将能够提取数据。

我建议单独匹配名称和地址行,如果你总是可以依赖字符串ORIGINAL位于与名称相同的行的右边,那么你可以单独编写正则表达式。正则表达式引擎将按顺序匹配模式,但您需要一些锚文本来清楚地搜索,然后获取相对于锚文本的值。然后,您需要解析并清理Match对象

中返回的值

<强>更新 我之前的回答部分经过编辑,以删除无关的信息

下面是一个包含解决方案的程序,Regex相对简单,所以我只是为那些不熟悉第一个模式语法的人打破它:

^[A-Z, ]+(?=original...)|^[A-Z, 0-9]+(?=balance...)|^[//A-Z, 0-9]+(?=past due...)|^[^\n\.]{2,50}(?=\n\s+\n^\s+THIS IS THE END OF THIS PAGE)  

正则表达式包含由|分割的4个单独模式,这意味着交替。

您可以测试模式here,注意不要添加任何额外字符,并确保检查多行并忽略大小写选项。

^捕获行的开头,因为我们通过Regex构造函数使用多行模式

[A-Z, ]捕获A-Z,逗号和空格

+重复出现前一个令牌1次或更多次,相当于说{1,}

(?=original....)预测此案例中的模式original....因此(?= 模式

The lookahead不会捕获字符,只会匹配。

其他模式是相似的,尽管最后一个模式匹配锚点之前的几个空白行。这是此页面的结尾并设置某些字符的最小/最大出现次数{2,50}

C#sample清除返回的标记 - 名称和地址 - 示例数据的7个项目。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

namespace RegexTester
{
    class Program
    {
        static string text = @"FIRST NOTICE                         COMPANYNAME
 NOTICE DATE....: 01/01/2001          1111 N NORTHWOOD DR
 NUMBER.........: 11-1-11111-1        SOMEWHERE WY 05920-5929
 THE DATE.......: 02/01/2001

 Some data only.







      DOEN, JOHN THOMAS                           ORIGINAL....:      5789.00
      1111 N WALT AVE                             BALANCE.....:      1000.00
      C/O SOMEONE ELSE                            PAST DUE....:       500.00
      SOMEWHERE WY 04741-5555

 THIS IS THE END OF THIS PAGE                     DATE DUE: 02/01/2001
 FIRST NOTICE                         COMPANYNAME
 NOTICE DATE....: 01/01/2001          1111 N NORTHWOOD DR
 NUMBER.........: 22-2-22222-2        SOMEWHERE WY 05920-5929
 THE DATE.......: 02/01/2001

 Some data only.







      DOE, JOHNAT ZOAR                            ORIGINAL....:      2211.00
      11111 N DIVISOR RD                          BALANCE.....:      2000.00
      SOMWEHERE WY 05922                          PAST DUE....:      1000.00


 THIS IS THE END OF THIS PAGE                     DATE DUE: 02/01/2001";

        static void Main(string[] args)
        {
            string pattern = @"^[A-Z, ]+(?=original...)|^[A-Z, 0-9]+(?=balance...)|^[//A-Z, 0-9]+(?=past due...)|^[^\n\.]{2,50}(?=\n\s+\n^\s+THIS IS THE END OF THIS PAGE)";
            Regex regex = new Regex(pattern, RegexOptions.Multiline | RegexOptions.IgnoreCase);
            MatchCollection matches = regex.Matches(text);
            List<string> cleaned = matches.Cast<Match>().Select(x => x.Value.Trim()).ToList();
        }
    }
}