繁体   English   中英

在多行之间包含字符的正则表达式

[英]Regex between and including characters across multiple lines

我有以下文字:

BEGIN:
>>DocTypeName: Zoning Letter
>>DocDate: 4/16/2014
Loan Number: 355211
Ad Hoc: ZONING VERIFICATION LETTER
Document Handle: 712826
>>DiskgroupNum: 102
>>VolumeNum: 367
>>NumOfPages: 0
>>FileSize: 261711
>>DocRevNum: 0
>>Rendition: 1
>>PhysicalPageNum: 0
>>ItemPageNum: 0
>>FileTypeNum: 16
>>ImageType: 0
>>Compress: 2
>>Xdpi: 0
>>Ydpi: 0
>>FileName: \V367\2855\1558564.PDF
BEGIN:
>>DocTypeName: Zoning Letter
>>DocDate: 4/16/2014
Loan Number: 355211
Ad Hoc: ZONING CODES COMPLIANCE LETTER
Document Handle: 712825
>>DiskgroupNum: 102
>>VolumeNum: 367
>>NumOfPages: 0
>>FileSize: 19441
>>DocRevNum: 0
>>Rendition: 1
>>PhysicalPageNum: 0
>>ItemPageNum: 0
>>FileTypeNum: 16
>>ImageType: 0
>>Compress: 2
>>Xdpi: 0
>>Ydpi: 0
>>FileName: \V367\2855\1558563.pdf

我需要使用正则表达式(将在C#程序中)将其转换为对CSV有效的内容。 最重要的数据是来自每个部分的文档句柄和文件名(路径)(作为“BEGIN:”下的部分)我正在为其他人工作,所以我想尽可能多地保留他们认为他们需要一些其他数据的事件。 这是我最初的尝试:

\r\n(?!BEGIN).*\:

但是,并非每个部分都有一个“Ad Hoc:”组件,当拉入Excel时会抛出单元格对齐。 我知道Ad Hoc肯定不是最终结果所需数据的一部分。

最好的情况是只选择并删除每个“Ad Hoc”和“Handle:”之间的所有内容,用分隔符(;)替换。 然后我会把它和我的上面的正则表达式一起管道。

我唯一的另一个要求是,这必须全部在一个正则表达式声明中 - 否则在我编写的程序中,我将不得不设置某种循环或业务,我还没准备好。

你可以使用正则表达式,但我不会说它比手动循环更容易。

(?<=BEGIN:\r\n)(?:.*:\s*(?:(?<value>(?<!Ad Hoc:\s*).*)|.*)(?:\r\n)?)*?(?=BEGIN:|$)

正则表达式可视化

示例代码:

foreach (Match m in Regex.Matches(text, @"(?<=BEGIN:\r\n)(?:.*:\s*(?:(?<value>(?<!Ad Hoc:\s*).*)|.*)(?:\r\n)?)*?(?=BEGIN:|$)"))
{
    Console.WriteLine(string.Join(",", m.Groups["value"].Captures.Cast<Capture>().Select(c => c.Value)));
}

输出:

Zoning Letter,4/16/2014,355211,712826,102,367,0,261711,0,1,0,0,16,0,2,0,0,\V367\2855\1558564.PDF
Zoning Letter,4/16/2014,355211,712825,102,367,0,19441,0,1,0,0,16,0,2,0,0,\V367\2855\1558563.pdf

基于我从问题下面的评论中理解的内容,问题中给出的示例数据应该转换为两个文本行,如下所示:

Zoning Letter;4/16/2014;355211;712826;102;367;0;261711;0;1;0;0;16;0;2;0;0;\V367\2855\1558564.PDF
Zoning Letter;4/16/2014;355211;712825;102;367;0;19441;0;1;0;0;16;0;2;0;0;\V367\2855\1558563.pdf

为了在避免循环的同时实现这个结果(虽然我想知道你为什么要避免循环 - 它们是基本的和全方位存在的结构),我建议应用两个(或三个,见下面的第3节)正则表达式替换。


1.删​​除“标签:”并用“;”替换换行符

第一个正则表达式将删除“:”前面的标签,包括“:”以及带分号的任何前面的换行符。 但是,它不会删除或替换“BEGIN:”前面的换行符,也不会触及“BEGIN:”本身。

@"(([\r\n]+\s*Ad\sHoc:.*?[\r\n]+)|([\r\n]+(?!\s*BEGIN))).*?:\s*"

正则表达式可视化

这个正则表达式是两个正则表达式的OR组合(在上面的可视化中很容易看到):

[\r\n]+\s*Ad\sHoc:.*?[\r\n]+.*?:\s*

这将匹配Ad Hoc:“行包括任何”Label:“字符串在下一行,和

([\r\n]+(?!\s*BEGIN)).*?:\s*

它将匹配任何“Label:”,包括它前面的换行符,除了“BEGIN:”标签。

将此正则表达式应用于您的示例并将所有匹配替换为“;” 将产生以下结果:

BEGIN:;Zoning Letter;4/16/2014;355211;712826;102;367;0;261711;0;1;0;0;16;0;2;0;0;\V367\2855\1558564.PDF
BEGIN:;Zoning Letter;4/16/2014;355211;712825;102;367;0;19441;0;1;0;0;16;0;2;0;0;\V367\2855\1558563.pdf

注意“开始:;” 我们现在要照顾。


2.删除“BEGIN:”标签

在查看第一个正则表达式替换的结果时,这是相当简单的模式。

"(?m)^BEGIN:;"

您可能认为可以通过字符串替换来完成此操作 - 在编写我的答案的第一个版本时也是如此。 但是,当“BEGIN:;”时,单纯的字符串替换会成为一个问题。 可以是任何其他文本字段的内容的一部分。 通过指定仅在行的开头匹配的正则表达式来更好地保持正确和安全。


3.代码示例,包括消除源文本中的空行

如果源文本中包含空格的空行,则上面显示的正则表达式可能无法正常工作。 解决方案是事先进行另一个正则表达式替换,这会将空行(包括空格)减少为单个换行符(如果您确定源数据不包含空行,则可以省略此步骤)。

一个完整的代码示例,它将产生我在答案开头提到的结果,可能如下所示:

string sourceData = ... your text with the source data ...

Regex reEmptyLines = new Regex(@"[\s\r\n]+[\r\n]", RegexOptions.Compiled);
Regex reSemicolons = new Regex(@"(([\r\n]+\s*Ad\sHoc:.*?[\r\n]+)|([\r\n]+(?!\s*BEGIN))).*?:\s*", RegexOptions.Compiled);
Regex reBegin = new Regex("(?m)^BEGIN:;", RegexOptions.Compiled);

string processed =
    reBegin.Replace(
        reSemicolons.Replace(
            reEmptyLines.Replace(sourceData, "\r\n"),
            ";"
        ),
        string.Empty
    );

这个怎么样:

BEGIN:((?:(?!BEGIN:).)*)

这将匹配第一个BEGIN和下一个BEGIN之间的所有内容。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM