我正在处理可能包含括号之间的内容的字符串,例如:
"Hello World"
"(Hello) World"
"(Hello World)"
"(Hello) (World)"
"bla bla (Hello World) bla bla"
"Hello (World"
我为此编写了一个简单的正则表达式:\((.*?)\)
:
var Inputs = new List<string>
{
"Hello World",
"(Hello) World",
"(Hello World)",
"(Hello) (World)",
"bla bla (Hello World) bla bla",
"Hello (World"
};
foreach (var input in Inputs)
{
var parts = Regex.Split(input, @"\((.*?)\)");
Console.WriteLine($"Input : {input}");
foreach (var part in parts)
{
Console.WriteLine($"> '{part}'");
}
Console.WriteLine("--------------------------------");
}
这给了我预期的输出:
Input : Hello World
> 'Hello World'
--------------------------------
Input : (Hello) World
> ''
> 'Hello'
> ' World'
--------------------------------
Input : (Hello World)
> ''
> 'Hello World'
> ''
--------------------------------
Input : (Hello) (World)
> ''
> 'Hello'
> ' '
> 'World'
> ''
--------------------------------
Input : bla bla (Hello World) bla bla
> 'bla bla '
> 'Hello World'
> ' bla bla'
--------------------------------
Input : Hello (World
> 'Hello (World'
--------------------------------
但是我需要对括号之间的捕获部分进行特殊处理。
我以为使用了命名组,例如(?<others1>.*?)\((?<choice>.*?)\)(?<others2>.*?)
,但是与组一起工作需要使用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("--------------------------------");
}
输出:
Input : Hello World // no match
--------------------------------
Input : (Hello) World // Missing ' World'
0: '(Hello)'
others1: ''
choice: 'Hello'
others2: ''
--------------------------------
Input : (Hello World) // Good
0: '(Hello World)'
others1: ''
choice: 'Hello World'
others2: ''
--------------------------------
Input : (Hello) (World) // Good
0: '(Hello)'
others1: ''
choice: 'Hello'
others2: ''
0: ' (World)'
others1: ' '
choice: 'World'
others2: ''
--------------------------------
Input : bla bla (Hello World) bla bla // missing last part ' bla bla'
0: 'bla bla (Hello World)'
others1: 'bla bla '
choice: 'Hello World'
others2: ''
--------------------------------
Input : Hello (World // no match
--------------------------------
是否可以使用Regex.Split()
使组名受益?
答案 0 :(得分:0)
坦率地说,这个问题遍及整个地图。您是否想要最终结果,或者想要解决此过程中的某个步骤?成为程序员的一部分是将事情分解成小步并在每个步骤上进行工作。您还没有这样做...所以让我们这样做:
那么您对哪个有疑问?提出SO问题时,只需将其咬成一小块即可。
看着bulk-email-generator problem,可以使用正则表达式来解决该问题,但是必须使用匹配项中找到的捕获组将项目正确分离。一旦它们分开,您就可以采用目标项目,该项目是在每次比赛后都会增加的索引。
示例
xxx (abc|def|ghi) yyy (ijk|lmn|opq) zzz
最终结果
xxx abc yyy lmn zzz
模式 这是模式,注释后进行解释。此正则表达式查找 OR 非组。从这些组中,它将单独的文本添加到内部捕获数组中:
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>[^(]+) #
";
请注意,我们将告诉regex解析器使用RegexOptions.IgnorePatternWhitespace
(允许我们在regex解析之前之前注释模式,还使用RegexOptions.ExplicitCapture
来注释正则表达式解析器中的任何内容)命名匹配捕获(?<NameHere> )
。
正则表达式结果
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
因此,如果分组为NonPiped
,我们将忽略“捕获”(只有一个)与火柴匹配的棍子。如果它是数据组之一,我们将重点放在Captures
上。
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++]
)
)
结果是xxx abc yyy lmn zzz
。
答案 1 :(得分:-1)
您可以使用稍有不同的正则表达式来保留括号:
var parts = Regex.Split(input, @"(\(.*?\))");
问题中的一个示例应报告:
Input : (Hello) World
> ''
> '(Hello)'
> ' World'
然后只需检查parts
的每个元素的开头和结尾字符是否包含方括号。
另一种方法将使用:
var parts = Regex.Split(input, @"([()])");
这应该产生:
Input : (Hello) World
> ''
> '('
> 'Hello'
> ')'
> ' World'
这也清楚地显示了方括号内的文本。