C# 如何使用Regex.Split获取组名

C# 如何使用Regex.Split获取组名,c#,regex,C#,Regex,我正在研究可能在括号之间包含内容的字符串,例如: "Hello World" "(Hello) World" "(Hello World)" "(Hello) (World)" "bla bla (Hello World) bla bla" "Hello (World" 为此我编写了这个简单的正则表达式:\(.*): 但是,我需要对括号之间捕获的部分进行特殊处理 我认为使用命名组,例如(?*?)\(?*?)(?*?),但是使用组需要使用Match()和GetGroupNames()等方法,我得

我正在研究可能在括号之间包含内容的字符串,例如:

"Hello World"
"(Hello) World"
"(Hello World)"
"(Hello) (World)"
"bla bla (Hello World) bla bla"
"Hello (World"
为此我编写了这个简单的正则表达式:
\(.*)

但是,我需要对括号之间捕获的部分进行特殊处理

我认为使用命名组,例如
(?*?)\(?*?)(?*?)
,但是使用组需要使用
Match()
GetGroupNames()
等方法,我得到了错误的结果:

// Inputs are the same than above
foreach (var input in Inputs)
{        
    var rgx = new Regex(@"(?<others1>.*?)\((?<choice>.*?)\)(?<others2>.*?)");

    var matches = rgx.Matches(input);
    var groups = rgx.GetGroupNames();


    Console.WriteLine($"Input : {input}");
    foreach (Match match in matches)
    {
        foreach (var group in groups)
        {
            Group grp = match.Groups[group];
            Console.WriteLine("   {0}: '{1}'", group, grp.Value);
            // if (group == "choice")
            //     SpecialTreatment(grp.Value);
        }
    }
    Console.WriteLine("--------------------------------");
}

是否有一种方法可以使组名受益于
Regex.Split()

您可以使用稍微不同的Regex来保留括号:

var parts = Regex.Split(input, @"(\(.*?\))");
问题中的一个例子应报告:

Input : (Hello) World
> ''
> '(Hello)'
> ' World'
然后,只需检查
部分
中每个元素的第一个和最后一个字符的括号


另一种办法是:

var parts = Regex.Split(input, @"([()])");
这将产生:

Input : (Hello) World
> ''
> '('
> 'Hello'
> ')'
> ' World'

这也清楚地显示了括号内的文本。

坦率地说,这个问题已经遍布整个地图。您是想要最终结果还是想要修复流程中的一个步骤?作为一名程序员的一部分是把事情分解成几个小步骤,并在每个步骤上工作。你还没有这么做…所以让我们这样做:

  • 匹配非分组文本或分组文本
  • 如果它是分组的,则将每个单独的项目分离到一个列表中
  • 如果未分组,则按原样处理
  • 如果是分组方案,则在重新组合时,取列表中比上一次操作索引+1的项
  • 那你对哪一个有意见?当你问一个简单的问题时,把它保持在一小块


    看一下,这个问题的答案可以使用regex来完成,但是必须使用在匹配中找到的捕获组来正确地分离项目。一旦它们被分离,那么你就可以获取目标项,它是一个索引,在每次匹配后都会增加

    示例

    xxx (abc|def|ghi) yyy (ijk|lmn|opq) zzz
    
    最终结果

     xxx abc yyy lmn zzz
    
    Match #0
                       [0]:  xxx
         ["Grouped"] → [1]:
      ["NotGrouped"] → [2]:  xxx
               →2 Captures: xxx
    Match #1
                       [0]:  (abc | def | ghi)
         ["Grouped"] → [1]:  ghi
               →1 Captures: abc, def, ghi
     ["NotGrouped"] → [2]:
    Match #2
                       [0]:   yyy
         ["Grouped"] → [1]:
      ["NotGrouped"] → [2]:   yyy
               →2 Captures: yyy
    Match #3
                       [0]:  (ijk | lmn | opq)
         ["Grouped"] → [1]:  opq
               →1 Captures: ijk, lmn, opq
     ["NotGrouped"] → [2]:
    Match #4
                       [0]:   zzz
         ["Grouped"] → [1]:
      ["NotGrouped"] → [2]:   zzz
               →2 Captures: zzz
    
    模式 下面是模式,请注释以进行解释。此正则表达式查找组或非组。从组内,它将单独的文本添加到内部捕获数组中:

    var pattern = @"          # Either its in a Group
     \(                            #(literal paren start)
         (
           (?<Grouped>[^|(]+)      # Match up to the pipe or paren
           \|?                     # Don't match the pipe but consume it if there
        )+                         # One to many of these piped items
     \)                               # (literal paren stop)
    |                          # Or its not in a group
     (?<NotGrouped>[^(]+)          #
    ";
    
    因此,如果分组是
    非管道的
    ,我们将忽略捕获(因为只有一个)与匹配本身的棍子。如果它是其中一个数据组,我们将重点关注
    捕获

    C#解决方案

    int index = 0;
    
    string.Join(string.Empty,
    
    Regex.Matches(text, pattern, RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture)
         .OfType<Match>()
         .Select(mtch => mtch.Groups["NotGrouped"].Success ? mtch.Groups["NotGrouped"].Value
                                                           : mtch.Groups["Grouped"].Captures
                                                                                   .OfType<Capture>()
                                                                                   .Select(cpt => cpt.Value)
                                                                                   .ToList()[index++]
                 )
    
        )
    
    int索引=0;
    Join(string.Empty,
    Regex.Matches(文本、模式、RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture)
    第()类
    .Select(mtch=>mtch.Groups[“NotGrouped”]。成功?mtch.Groups[“NotGrouped”]。值
    :mtch.Groups[“Grouped”]。捕获
    第()类
    .Select(cpt=>cpt.Value)
    .ToList()[index++]
    )
    )
    

    结果是模式末尾的xxx abc yyy lmn zzz

    *?
    从不匹配任何字符。为什么需要命名组?您不需要它们,这是一个XY问题。请解释你最终需要达到的目标。那么,你有了
    bla-bla(Hello World)bla-bla
    ,你到底需要得到什么?@WiktorStribiżew我刚刚弄明白为什么
    *?
    在最后是无用的,这是惰性匹配,空字符串将匹配。我需要应用一个
    String.Split()
    ,然后对
    (…)
    进行一些只匹配的计算,这就是为什么我认为使用名称可以帮助我识别这些部分。对于
    bla bla bla(Hello World)bla bla
    ,我需要检索
    ()
    之前、之后和内部的部分,因此,您的代码可以工作。为什么要改变它?为什么要问一个问题?是的,这个问题被很多人误解了。另外,你并不真的需要你描述的检查,你可以使用我的方法。看,这几乎是这个问题的一个愚蠢的理由。
    var pattern = @"          # Either its in a Group
     \(                            #(literal paren start)
         (
           (?<Grouped>[^|(]+)      # Match up to the pipe or paren
           \|?                     # Don't match the pipe but consume it if there
        )+                         # One to many of these piped items
     \)                               # (literal paren stop)
    |                          # Or its not in a group
     (?<NotGrouped>[^(]+)          #
    ";
    
    Match #0
                       [0]:  xxx
         ["Grouped"] → [1]:
      ["NotGrouped"] → [2]:  xxx
               →2 Captures: xxx
    Match #1
                       [0]:  (abc | def | ghi)
         ["Grouped"] → [1]:  ghi
               →1 Captures: abc, def, ghi
     ["NotGrouped"] → [2]:
    Match #2
                       [0]:   yyy
         ["Grouped"] → [1]:
      ["NotGrouped"] → [2]:   yyy
               →2 Captures: yyy
    Match #3
                       [0]:  (ijk | lmn | opq)
         ["Grouped"] → [1]:  opq
               →1 Captures: ijk, lmn, opq
     ["NotGrouped"] → [2]:
    Match #4
                       [0]:   zzz
         ["Grouped"] → [1]:
      ["NotGrouped"] → [2]:   zzz
               →2 Captures: zzz
    
    int index = 0;
    
    string.Join(string.Empty,
    
    Regex.Matches(text, pattern, RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture)
         .OfType<Match>()
         .Select(mtch => mtch.Groups["NotGrouped"].Success ? mtch.Groups["NotGrouped"].Value
                                                           : mtch.Groups["Grouped"].Captures
                                                                                   .OfType<Capture>()
                                                                                   .Select(cpt => cpt.Value)
                                                                                   .ToList()[index++]
                 )
    
        )