需要在 C# 正则表达式中提取文本
Posted
技术标签:
【中文标题】需要在 C# 正则表达式中提取文本【英文标题】:Need to extract text in a C# Regex 【发布时间】:2021-08-21 18:35:34 【问题描述】:我有一个字符串集合,例如Some song [FEAT. John Doe]
,我正在尝试提取“特色”部分。它可以通过几个不同的词之一来标识"FEAT|FEAT\\.|Featuring"
,并且可以用括号括起来也可以不括起来。我正在为此使用正则表达式,这就是我到目前为止所得到的:
[TestMethod]
public void ExtractFeaturedPerformers()
IEnumerable<string> titles = new string[]
"abc [FEAT one two] 123",
"def(FEAT. three'four) 456",
"ghi Featuring five",
"jkl"
;
// Must be able to use an arbitrary array of words
var arrayOfWords = new string[] "FEAT", "FEAT.", "Featuring" ;
string options = string.Join("|", arrayOfWords.Select(s => Regex.Escape(s)));
var result = new List<string>();
foreach(string title in titles)
var _ = Regex.Match(title, $@"(?<=(options)\s*)(.*?)(?=[\]\)]|$)");
if (_.Success)
result.Add(_.Value);
Assert.AreEqual(3, result.Count());
Assert.IsTrue(result.Contains("one two"));
Assert.IsTrue(result.Contains("three'four"));
Assert.IsTrue(result.Contains("five"));
我大部分时间都在工作,但有两个限制。我的主要问题是第二个结果包括.
。
. three'four
如何将其作为 Regex 的一部分删除,以便我可以接受任意的 options
字符串,而不是稍后将其剥离?处理.
是我主要关心的问题,但我也很感激从结果中删除前导和尾随空格的建议,这样我以后就不必再调用Trim()
了。
【问题讨论】:
【参考方案1】:你需要
(?:FEAT\.?|Featuring)\s*([^])]*)
见regex demo
详情
(?:FEAT\.?|Featuring)
- FEAT
和可选的 .
或 Featuring
\s*
- 零个或多个空格
([^])]*)
- 正在捕获组 1:除 ]
和 )
之外的零个或多个字符。
您需要修改 C# 代码以获取第 1 组值。
这里是full C# demo:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
public class Test
public static void Main()
IEnumerable<string> titles = new string[]
"abc [FEAT one two] 123",
"def(FEAT. three'four) 456",
"ghi Featuring five",
"jkl"
;
var keys = new List<string> "FEAT", "FEAT.", "Featuring" ;
keys = keys.OrderByDescending(x => x.Length).ToList();
var pattern = $@"(?:string.Join("|", keys.Select(z => Regex.Escape(z))))\s*([^])]*)";
Console.WriteLine(pattern);
var result = new List<string>();
foreach(string title in titles)
var _ = Regex.Match(title, pattern);
if (_.Success)
result.Add(_.Groups[1].Value);
Console.WriteLine( result.Count()); // Assert.AreEqual(3, result.Count());
Console.WriteLine( result.Contains("one two") ); //Assert.IsTrue(result.Contains("one two"));
Console.WriteLine( result.Contains("three'four") ); //Assert.IsTrue(result.Contains("three'four"));
Console.WriteLine( result.Contains("five") ); // Assert.IsTrue(result.Contains("five"));
输出是
(?:Featuring|FEAT.|FEAT)\s*([^])]*)
3
True
True
True
注意正则表达式模式是如何构建的:
var keys = new List<string> "FEAT", "FEAT.", "Featuring" ;
使用搜索短语初始化 keys
字符串列表
keys = keys.OrderByDescending(x => x.Length).ToList();
- 按长度降序对列表中的项目进行排序
var pattern = $@"(?:string.Join("|", keys.Select(z => Regex.Escape(z))))\s*([^])]*)";
- 通过将转义的搜索短语放入非捕获组中创建正则表达式模式,其中|
交替运算符(?:Featuring|FEAT\.|FEAT)
。
【讨论】:
为什么要放弃 Lookbehind 解决方案? @41686d6564 因为后视中的可选.
很麻烦。由于正则表达式引擎从左到右搜索匹配项,FEAT
之前的位置会更早找到,并且匹配项中仍会出现点。使用消费模式时,可选点将被消费,并且不会出现在 Group 1 值中。如果Feat
部分之后总是有一个空格,(?<=(?:FEAT\.?|Featuring)\s)([^])]*)
可能会起作用。在这些情况下,捕获机制更安全。
啊,我总是忘记 Lookbehinds 的这个警告。谢谢你,维克托。我站得更正。 :)
感谢您的回答 Wiktor。它适用于 FEAT
、FEAT.
和 Featuring
。唯一的麻烦是,我需要能够接受任意字符串。
@Connell.O'Donnell 你的意思是像string options = string.Join("|", collectionOfWords.Select(s => Regex.Escape(s)));
吗?以上是关于需要在 C# 正则表达式中提取文本的主要内容,如果未能解决你的问题,请参考以下文章