正则表达式 - 相同模式的多个出现之间的文本

时间:2017-07-08 00:37:53

标签: c# regex

我需要解析大量文件并根据某些令牌处理一些内容。为了做到这一点,我必须将每个标记和文本放在它之后,直到下一个标记(带有额外的新行)。

A ---
some text of many lines
B --- 

other text with some lines

C --- 
more text and tokens and text

我一直在使用regex101并将其拆分

(?<token>^([a-zA-Z].--.*))|(?<content>.*)

但是,我无法在单个组中获得第二场比赛。 期望的结果是获得成对的令牌和文本。

使用单个正则表达式表达式可以实现此目的吗?怎么样?

由于

2 个答案:

答案 0 :(得分:2)

以下是我能够使你的正则表达式工作的原因。

/(?<token>[A-Za-z]+)\s*---\s*(?<content>.+?)(?=[A-Za-z]+\s*---\s*|$)/gs

https://regex101.com/r/x8tPHN/4

我拥有的和你拥有的东西之间的区别在于,有一个前瞻,它会检查新令牌或数据的结尾。

我启用了g(全局)和s(点等于新行)标志。

答案 1 :(得分:2)

我们假设您的token模式是正确的,并且匹配您需要的所有模式。然后,内容是token模式之后的所有内容,直到第一次出现令牌模式,即^[a-zA-Z].--.*:行的开头(^),一个ASCII字母({{ 1}}),任何字符,但换行符([a-zA-Z]),两个连字符(.),然后任意多个字符,尽可能多,直到行的末尾(注意,在.NET正则表达式--也匹配CR .符号。

如果您的文件不是那么大,可以使用

"\r"

请参阅regex demo。此正则表达式解释了令牌没有内容时的情况,并且还排除了在某些内容中间匹配令牌的情况。

从结构的角度来看,模式等于(?m)^(?<token>[a-zA-Z].--.*)(?<content>(?s:.*?))(?=^[a-zA-Z].---|\z),但是是一个更有效的版本,因为懒惰的点匹配模式受到前瞻性的限制,有两个选择使得正则表达式引擎在匹配每个时都很难输入字符串中的char。像我建议的那样展开的模式将抓住不同时以令牌开头的整行,因此它将更快地工作。

<强>详情:

  • @"(?m)^(?<token>[a-zA-Z].--.*)(?<content>(?:\r?\n(?![a-zA-Z].---).*)*)" - 与(?m)相同,RegexOptions.Multiline匹配立即开始(^匹配行的结尾,而不是整个字符串
  • $ - 行的开头
  • ^ - “令牌”组:
    • (?<token>[a-zA-Z].--.*) - ASCII字母
    • [a-zA-Z] - 任何字符,但换行符(也匹配CR,使用.仅匹配不属于CRLF结尾的字符)
    • [^\n\r] - 两个连字符
    • -- - 除了换行符之外的任何0 +字符,尽可能多,直到行的末尾(注意.*与.NET正则表达式中的CR匹配)
  • . - “内容”组:
    • (?<content>(?:\r?\n(?![a-zA-Z].---).*)*) - 零个或多个序列:
      • (?:\r?\n(?![a-zA-Z].---).*)* - CRLF或LF行末尾未跟随令牌模式
      • \r?\n(?![a-zA-Z].---) - 除了换行符之外的任何0 +字符,尽可能多,直到行尾

C# demo(注意我正在修剪组值以摆脱前导/尾随空格):

.*

输出:

var s = "A ---\r\nsome text of many lines\r\nB ---\r\n\r\nother text with some lines\r\nand text and\r\ntext \r\n\r\nC --- \r\nmore text and tokens and text\r\n\r\nQQ--- \r\n\r\nmore text more text\r\n\r\nHH---\r\nJJ---\r\n";
var pat = @"^(?<token>[a-zA-Z].--.*)(?<content>(?:\r?\n(?![a-zA-Z].---).*)*)";
var result = Regex.Matches(s, pat, RegexOptions.Multiline)
        .Cast<Match>()
        .Select(m => new[] {m.Groups["token"].Value.Trim(), m.Groups["content"].Value.Trim()});
foreach (var pair in result)
    Console.WriteLine($"--- New match ---\nToken: {pair[0]}\nContent: {pair[1]}");