C#正则表达式拆分字符串并在拆分

时间:2016-11-27 14:11:57

标签: c# regex linq

我有以下字符串:

Bacon ipsum dolor amet **kevin kielbasa** pork chop picanha chuck, 
t-bone **brisket corned beef fatback hamburger cow** sirloin shank prosciutto
shankle. T-bone pancetta ribeye **tongue** fatback drumstick frankfurter short 
ribs burgdoggen. **Tail cupim.**

我想获得:

List<string>(){
    "Bacon ipsum dolor amet ",
    "**kevin kielbasa**",
    " pork chop picanha chuck, t-bone ",
    "**brisket corned beef fatback hamburger cow**",
    " sirloin shank prosciutto shankle. T-bone pancetta ribeye ",
    "**tongue**",
    " fatback drumstick frankfurter short ribs burgdoggen. ",
    "**Tail cupim.**"
}

的方法:

  1. 完全在正则表达式中:
  2. 首次通过

    Regex.Split(str, @"\*\*.*?\*\*");

    "Bacon ipsum dolor amet ",
    " pork chop picanha chuck, t-bone ",
    " sirloin shank prosciutto shankle. T-bone pancetta ribeye ",
    " fatback drumstick frankfurter short ribs burgdoggen. "
    

    拆分删除所有匹配的项目。它将每一个视为它认为我们想要的项目之间的分隔符。 d&#39;!哦

    第二次通过

    Regex.Matches(str, @"\*\*.*?\*\*").Cast<Match>().Select(m => m.Value).ToList();

    "**kevin kielbasa**",
    "**brisket corned beef fatback hamburger cow**",
    "**tongue**",
    "**Tail cupim.**"
    

    嗯,这是有道理的。 Regex.Matches()会返回与正则表达式匹配的所有项目,因此我们已经丢失了所有内容。

    1. 用一点LINQ:
    2. 好的,让我们看看我们是否可以将所有文本放在一个列表中:

      Regex.Split(str, @"\*\*");

      "Bacon ipsum dolor amet ",
      "kevin kielbasa",
      " pork chop picanha chuck, t-bone ",
      "brisket corned beef fatback hamburger cow",
      " sirloin shank prosciutto shankle. T-bone pancetta ribeye ",
      "tongue",
      " fatback drumstick frankfurter short ribs burgdoggen. ",
      "Tail cupim."
      

      奇怪的是,这个简单的正则表达式让我们最接近,但我们不再知道列表中的哪些项目被**包围了。因为**会替换每个列表项,所以我们需要知道的是列表中的第一个(或第二个)项是否被**包围。

      bool firstIsMatch = "**" == new string(str.Take(2).ToArray());

      然后我们可以使用该bool来确定我们是否正在添加&#34; **&#34;到列表中每个偶数或奇数项的开头和结尾。

      问题:

      • 有没有办法完全使用正则表达式?如果是这样,怎么样?
      • 尽管是&#34;更多代码&#34;,是性能和/或可读性首选的第二个选项?

3 个答案:

答案 0 :(得分:2)

如何在正则表达式中使用Regex.Matches管道,例如

(?s)\*\*.*?\*\*|.+?(?=\*\*|$)

See demo at regex storm

中的lookahead要在**$结束前停止。

答案 1 :(得分:2)

您只需将正则表达式包装在捕获组中即可。一旦正则表达式找到要拆分的匹配项,匹配文本也将被推送到结果数组中。请参阅Regex.Split参考:

  

如果在Regex.Split表达式中使用捕获括号,任何捕获的文本都包含在生成的字符串数组中。例如,如果你拆分字符串&#34; plum-pear&#34;在捕获括号内的连字符上,返回的数组包含一个包含连字符的字符串元素。

以后可以使用LINQ:

轻松过滤掉空元素
var str  = "Bacon ipsum dolor amet **kevin kielbasa** pork chop picanha chuck, t-bone **brisket corned beef fatback hamburger cow** sirloin shank prosciutto shankle. T-bone pancetta ribeye **tongue** fatback drumstick frankfurter short ribs burgdoggen. **Tail cupim.**";
var res = Regex.Split(str, @"(\*{2}.*?\*{2})", RegexOptions.Singleline) // Split and keep  the captures
        .Where(s=>!string.IsNullOrWhiteSpace(s)); // Remove blank elements
Console.WriteLine("\"{0}\"", string.Join("\"\n\"", res));

请参阅C# demo

关于模式性能的一个小注释:如果文本非常大,由于懒惰的点匹配模式,您可能会遇到减速。最好将其展开为@"\*{2}[^*]*(?:\*(?!\*)[^*]*)*\*{2}",特别是如果有少量的#34; wild&#34;,独立的星号(分隔符)。

答案 2 :(得分:1)

请尝试以下方法:

var s = "Bacon ipsum dolor amet **kevin kielbasa** pork chop picanha chuck, " +
"t-bone **brisket corned beef fatback hamburger cow** sirloin shank prosciutto " +
"shankle. T-bone pancetta ribeye **tongue** fatback drumstick frankfurter short " +
"ribs burgdoggen. **Tail cupim.**";

var split = Regex.Split(s, @"(?=\*\*\S)|(?<=\S\*\*)");

foreach (var part in split)
{
    Console.WriteLine(part);
}

// == OUTPUT ==
//
// Bacon ipsum dolor amet 
// **kevin kielbasa**
//  pork chop picanha chuck, t-bone 
// **brisket corned beef fatback hamburger cow**
//  sirloin shank prosciutto shankle. T-bone pancetta ribeye 
// **tongue**
//  fatback drumstick frankfurter short ribs burgdoggen. 
// **Tail cupim.**