捕获组之间的 C# 正则表达式空白
C# Regex whitespace between capturing groups
所以基本上,我的输入字符串是某种包含我想要匹配的关键字的文本,前提是:
- 每个关键字可能有 whitespace/non-word 个字符 pre/appended,或 none
(|\s\W)
- 必须恰好有一个 non-word/whtiespace 字符分隔多个关键字,或者关键字位于第 begining/end 行
- 仅作为子字符串出现的关键字不算数,例如
bar
不匹配 foobarbaz
例如:
input: "#foo barbazboo tree car"
keywords: {"foo", "bar", "baz", "boo", "tree", "car"}
我正在使用可枚举的关键字和字符串生成器在 C# 中动态生成正则表达式
StringBuilder sb = new();
foreach (var kwd in keywords)
{
sb.Append($"((|[\s\W]){kwd}([\s\W]|))|");
}
sb.Remove(sb.Length - 1, 1); // last '|'
_regex = new Regex(sb.ToString(), RegexOptions.Compiled | RegexOptions.IgnoreCase);
在 regexr.com 上测试此模式,给定的输入匹配所有关键字。但是,我不想包含 {bar, baz, boo}
,因为每个关键字之间没有空格。
理想情况下,我希望我的正则表达式只匹配 {foo, tree, car}
.
像 (( |[\s\W])kwd([\s\W]| ))
这样修改我的模式会导致 {bar, baz, boo}
不被包含,但会在 {tree, car}
上产生伪造,因为对于这种情况,关键字之间必须至少有两个空格。
如何指定“可能只有一个空格分隔两个关键字”,或者换句话说,“半个空格就可以”,保留动态创建正则表达式的能力?
对于您的情况,您需要构建
var pattern = $@"\b(?:{string.Join("|", keywords.OrderByDescending(x => x.Length).Select(Regex.Escape))})\b";
_regex = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
在这里,您会在较短的关键字之前获得较长的关键字,因此,如果您有 foo
、bar
和 foo bar
,则模式将类似于 \b(?:foo\ bar|foo|bar)\b
并将匹配 foo bar
,而不是 foo
和 bar
一旦有这样的匹配。
如果您的关键字看起来像 keywords: {"$foo", "^bar^", "[baz]", "(boo)", "tree+", "+car"}
,即它们可以在关键字的 start/end 处有特殊字符,您可以使用
_regex = new Regex($@"(?!\B\w)(?:{string.Join("|", keywords.Select(Regex.Escape))})(?<!\w\B)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
$@"(?!\B\w)(?:{string.Join("|", keywords.OrderByDescending(x => x.Length).Select(Regex.Escape))})(?<!\w\B)"
是一个内插的逐字字符串文字,其中包含
(?!\B\w)
- left-hand
(?:
- non-capturing 组的开始:
{string.Join("|", keywords.OrderByDescending(x => x.Length).Select(Regex.Escape))}
- 按长度降序排列关键字,将它们转义并加入 |
)
- 小组结束
(?<!\w\B)
- right-hand自适应动态字边界。
所以基本上,我的输入字符串是某种包含我想要匹配的关键字的文本,前提是:
- 每个关键字可能有 whitespace/non-word 个字符 pre/appended,或 none
(|\s\W)
- 必须恰好有一个 non-word/whtiespace 字符分隔多个关键字,或者关键字位于第 begining/end 行
- 仅作为子字符串出现的关键字不算数,例如
bar
不匹配foobarbaz
例如:
input: "#foo barbazboo tree car"
keywords: {"foo", "bar", "baz", "boo", "tree", "car"}
我正在使用可枚举的关键字和字符串生成器在 C# 中动态生成正则表达式
StringBuilder sb = new();
foreach (var kwd in keywords)
{
sb.Append($"((|[\s\W]){kwd}([\s\W]|))|");
}
sb.Remove(sb.Length - 1, 1); // last '|'
_regex = new Regex(sb.ToString(), RegexOptions.Compiled | RegexOptions.IgnoreCase);
在 regexr.com 上测试此模式,给定的输入匹配所有关键字。但是,我不想包含 {bar, baz, boo}
,因为每个关键字之间没有空格。
理想情况下,我希望我的正则表达式只匹配 {foo, tree, car}
.
像 (( |[\s\W])kwd([\s\W]| ))
这样修改我的模式会导致 {bar, baz, boo}
不被包含,但会在 {tree, car}
上产生伪造,因为对于这种情况,关键字之间必须至少有两个空格。
如何指定“可能只有一个空格分隔两个关键字”,或者换句话说,“半个空格就可以”,保留动态创建正则表达式的能力?
对于您的情况,您需要构建
var pattern = $@"\b(?:{string.Join("|", keywords.OrderByDescending(x => x.Length).Select(Regex.Escape))})\b";
_regex = new Regex(pattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);
在这里,您会在较短的关键字之前获得较长的关键字,因此,如果您有 foo
、bar
和 foo bar
,则模式将类似于 \b(?:foo\ bar|foo|bar)\b
并将匹配 foo bar
,而不是 foo
和 bar
一旦有这样的匹配。
如果您的关键字看起来像 keywords: {"$foo", "^bar^", "[baz]", "(boo)", "tree+", "+car"}
,即它们可以在关键字的 start/end 处有特殊字符,您可以使用
_regex = new Regex($@"(?!\B\w)(?:{string.Join("|", keywords.Select(Regex.Escape))})(?<!\w\B)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
$@"(?!\B\w)(?:{string.Join("|", keywords.OrderByDescending(x => x.Length).Select(Regex.Escape))})(?<!\w\B)"
是一个内插的逐字字符串文字,其中包含
(?!\B\w)
- left-hand(?:
- non-capturing 组的开始:{string.Join("|", keywords.OrderByDescending(x => x.Length).Select(Regex.Escape))}
- 按长度降序排列关键字,将它们转义并加入|
)
- 小组结束(?<!\w\B)
- right-hand自适应动态字边界。