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

C# 是否可以使用正则表达式提取不同的文本块和多行?,c#,regex,C#,Regex,我想使用正则表达式从报表文档中提取不同的文本块-每个新页面在“FIRST NOTICE”(第一个通知)前面用\x0c表示[下面未显示]。我已经包括了一张带有行号的图片和文本,尽管格式可能有问题 报告文本将包含1..n页-返回数据时,每一页都是单独的行项目。这些数据将被提取并转换成行,输入数据库[编号、余额、名称、地址1、地址2、城市、州、邮政编码] 我需要提取的数据片段: 编号-11-1-11111-1 余额-1000.00 名称-“多恩,约翰·托马斯”[第14行,第7-50列] 地址-2至3行

我想使用正则表达式从报表文档中提取不同的文本块-每个新页面在“FIRST NOTICE”(第一个通知)前面用\x0c表示[下面未显示]。我已经包括了一张带有行号的图片和文本,尽管格式可能有问题

报告文本将包含1..n页-返回数据时,每一页都是单独的行项目。这些数据将被提取并转换成行,输入数据库[编号、余额、名称、地址1、地址2、城市、州、邮政编码]

我需要提取的数据片段:

  • 编号-11-1-11111-1
  • 余额-1000.00
  • 名称-“多恩,约翰·托马斯”[第14行,第7-50列]
  • 地址-2至3行
  • 进一步-分为Addr1/Addr2/City/State/Zip
  • 与城市的界线:城市圣齐普4或Zip-9
  • 城市可以包含空间
  • 数字和余额相对容易获得-这是名称和地址部分,我有最大的问题,并寻找一个单一的正则表达式,将每个项目纳入自己的组

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

    这可能吗

    包含两页的示例文档:


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

    Regex reg = new Regex(@"pattern1|pattern2", RegexOptions.Multiline);
    var matches = reg.Matches("my text with /n lines");
    
    Regex的另一个方面是,您可以将模式划分为相当于要匹配的备用文本的段。请参阅上的这篇文章。使用从reg.Matches返回的MatchCollection,您将能够提取数据

    我建议分别在名称行和地址行上进行匹配,例如,如果您可以始终依赖于与名称位于同一行右侧的字符串,那么您可以分别为此编写正则表达式。正则表达式引擎将按顺序匹配模式,但您需要一些锚文本来清晰地搜索,然后获取相对于锚文本的值。然后需要解析并清除Match对象返回的值

    更新 我之前的回答被部分编辑以删除无关信息

    下面是一个包含解决方案的程序,正则表达式相对简单,因此我将为那些不熟悉第一个模式语法的人详细介绍:

    ^[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个独立模式,这意味着交替

    您可以小心地测试模式,不要添加任何额外字符,并确保选中多行和忽略大小写选项

    ^
    通过正则表达式构造函数使用多行模式时捕获行的开头

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

    +
    重复前面标记的出现1次或多次,相当于说
    {1,}

    (?=original…)
    在本例中查找模式
    original…
    因此(?=pattern)

    不捕获字符,只捕获匹配项

    其他模式类似,但最后一个模式与锚之前的两个空行相匹配。这是本页的结尾,并在某些字符上设置最小/最大出现次数
    {2,50}

    C#清理返回的令牌的示例-名称和地址-示例数据的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();
            }
        }
    }
    
    使用系统;
    使用System.Collections.Generic;
    使用System.Linq;
    使用System.Text.RegularExpressions;
    名称空间RegexTester
    {
    班级计划
    {
    静态字符串text=@“第一个通知公司名称”
    通知日期:2001年1月1日北纬1111诺思伍德博士
    编号:11-1-11111-1 WY 05920-5929
    日期:2001年1月2日
    只有一些数据。
    多恩,约翰·托马斯原件:5789.00
    华尔特大道1111号余额……:1000.00
    转交其他逾期未付的人….:500.00
    WY 04741-5555某处
    本页到此结束日期截止日期:2001年1月2日
    第一通知公司名称
    通知日期:2001年1月1日北纬1111诺思伍德博士
    编号:22-2-22222-2 WY 05920-5929
    日期:2001年1月2日
    只有一些数据。
    能源部,约翰纳特·佐尔原版….:2211.00
    11111 N除数RD余额…:2000.00
    索姆韦赫WY 05922逾期….:1000.00
    这是本页的结尾日期截止日期:2001年1月2日”;
    静态void Main(字符串[]参数)
    {
    字符串模式=@“^[A-Z,]+(?=原始…)^[A-Z,0-9]+(?=余额…)^[///A-Z,0-9]+(?=过期…)^[^\n\.]{2,50}(?=\n\s+\n^\s+这是本页的结尾)”;
    Regex Regex=new Regex(模式,RegexOptions.Multiline | RegexOptions.IgnoreCase);
    MatchCollection matches=regex.matches(文本);
    List=matches.Cast().Select(x=>x.Value.Trim()).ToList();
    }
    }
    }
    
    它支持多行,理解-但是,我不知道如何告诉它提取姓名/地址行。@MatthewM。公平地说,现在没有时间考虑正则表达式,但如果需要,可以稍后再查看。是的,原始/BLANACE/过期总是存在,并且将处于这些位置。我不认为我可以使用这些,虽然我没有做太多的前瞻性/落后。我想可选的没有锚定的第三个地址行可以锚定到“THIS IS the END OF THIS PAGE”?不过,我还是不确定具体细节。@MatthewM。如果它能让你开始,我写了一篇博文,试图解释“环顾四周”——它可能会让你开始。查找与括号字符有关(并搜索术语和/或或你..是..太棒了!非常感谢。我刚刚完成了自己的版本..(\d{2}-\d)-
    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();
            }
        }
    }