c# - 如何使用 Regex.Split 获取组名称
问题描述
我正在处理可能包含括号之间的内容的字符串,例如:
"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()
and之类的方法,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()
?
解决方案
坦率地说,这个问题无处不在。您想要最终结果还是想要修复过程中的一个步骤?作为程序员的一部分是将事情分解成小步骤并在每个步骤上工作。你还没有这样做......所以让我们这样做:
- 匹配非分组文本或分组文本。
- 如果它被分组,则将每个单独的项目分离到一个列表中。
- 如果它未分组,则按原样处理。
- 如果是分组场景,则在重新组合时,获取列表中比上一个操作索引 +1 的项目。
那么你对哪个有问题?当问一个 SO 问题时,只需将其保留为一小块。
查看bulk-email-generator 问题,该问题的答案可以使用正则表达式来完成,但必须使用匹配中找到的捕获组来正确分离项目。将它们分开后,您可以获取目标项目,该项目是每次匹配后都会增加的索引。
例子
xxx (abc|def|ghi) yyy (ijk|lmn|opq) zzz
最终结果
xxx abc yyy lmn 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>[^(]+) #
";
请注意,我们将告诉正则表达式解析器使用RegexOptions.IgnorePatternWhitespace
(允许我们在正则表达式解析之前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(因为只有一个)匹配本身。如果它是数据组之一,我们将重点放在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
。
推荐阅读
- python - 新手根本无法获得concurrent.futures
- html - 图像/文本超链接 - HTML/CSS
- javascript - FlatList 中的 ExtraData 在更改时不会更新列表
- postgresql - PostgreSQL 错误:无法扩展文件,设备上没有剩余空间
- kubernetes - Statefulset - 创建和重新启动后如何自动为 pod 设置标签?
- flutter - 如何在颤动中制作自定义和单选芯片或单选按钮
- android - 为什么 Google 要将新的开发者推向 Kotlin 的 Android 应用程序?
- laravel - 多对多中间表如何访问表中的字段?
- javascript - 如何在 Fabric JS 中获取作为 JSON 上传的 Canvas 上的项目 ID?
- validation - 通过验证从弹出窗口中捕获用户输入?