更新
对于那些询问为什么不使用 String.Substring 的人:正则表达式相对于字符串操作的最大优势在于它们不会生成临时字符串,直到您真正要求匹配的值。匹配项和组仅包含源字符串的索引。这在处理日志文件时是一个巨大的优势。
您可以使用像
这样的正则表达式来匹配标签的内容
Tag\s*=\s*"(<tagValue>.*?)"
.*? 中的? 导致非贪婪搜索,即只提取到 first 双引号的文本。否则,该模式将匹配直到最后一个双引号的所有内容。
(<tagValue>.*?) 定义了一个命名组。这样你就可以引用 name 捕获的实际值,甚至可以使用 LINQ 来处理这些值
转义后生成的 C# 代码可能如下所示:
var myRegex=new Regex("Tag\\s*=\\s*\"(<tagValue>.*?)\"");
...
var tags=myRegex.Matches(someText)
.OfType<Match>()
.Select(match=>match.Groups["tagValue"].Value);
结果是一个包含所有标签值的 IEnumerable。您可以使用 ToArray() 或 ToList() 将其转换为数组或列表,就像任何其他 IEnumerable 一样
使用循环的等效代码是
var myRegex=new Regex("Tag\\s*=\\s*\"(<tagValue>.*?)\"");
...
List<string> tagValues=new List<string>();
foreach(Match m in myRegex.Matches(someText))
{
tagValues.Add(m.Groups["tagValue"].Value;
}
LINQ 版本虽然可以很容易地扩展。例如,File.ReadLines 返回一个 IEnumerable 并且不会等待在返回之前将所有内容加载到内存中。你可以这样写:
var tags=File.ReadLines(myBigLog)
.SelectMany(line=>myRegex.Matches(line))
.OfType<Match>()
.Select(match=>match.Groups["tagValue"].Value);
如果标签名称发生变化,您还可以捕获标签名称。如果 eg 标签有 tag 前缀,您可以使用该模式:
(?<tagName>tag\w+)\s*=\s*"(<tagValue>.*?)"
并在Select函数中提取标签名称和值,例如:
.Select(match=>new {
TagName=match.Groups["tagName"].Value,
Value=match.Groups["tagValue"].Value
});
Regex.Matches 是线程安全的,这意味着您可以创建一个静态 Regex 对象并重复使用它,甚至只需在调用 SelectMany 之前添加 AsParallel() 即可使用 PLINQ 并行匹配多行。