【问题标题】:Stripping text line with regular expression with c #用c#用正则表达式剥离文本行
【发布时间】:2016-08-10 09:05:44
【问题描述】:

在下面显示的文本中,我需要提取双引号之间的信息(输入是文本文件)

Tag = "571EC002A-TD"

Tag = "571GI001-RUN"

Tag = "571GI001-TD"

输出应该是,

571EC002A-TD

571GI001-RUN

571GI001-TD

我应该如何在 C# 中构建我的正则表达式以匹配它并将其保存到文本文件中。

在将所有行读入我的代码之前我是成功的,但是正则表达式给了我一些不受欢迎的值。

提前感谢和感谢。

【问题讨论】:

  • 发布正则表达式的代码
  • 其实这似乎可以通过简单的Substring
  • 只允许有解析大型日志文件或使用 Splunk 执行相同操作经验的人员对此问题投反对票。不要对你不理解的内容投反对票
  • 哪个 regex 给了我一些不受欢迎的值?问题中没有正则表达式。
  • @Rakitić,你的字符串应该是string Tag = "Tag = \"571EC002A-TD\"";。此外,该选项已发布在答案中。

标签: c# regex


【解决方案1】:

一个简单的正则表达式可以是:

Regex tagRegex = new Regex(@"Tag\s?=\s?""(.+?)""");

Example with your input

【讨论】:

  • 为什么是+??如果字符串恰好在中间有一个",它将停在那里。虽然这不太可能发生。
  • 您不需要在正则表达式中转义双引号。如果你想创建一个正确的 C# 字符串,你应该同时转义\ ",即Tag\\s?=\\s?\"(.+?)\"。最后要说明一下OP可以通过Match.Groups访问内容
  • OP 写道他已经尝试了一些正则表达式 - 所以我认为他熟悉用法。
  • 就像@PanagiotisKanavos 说的那样,我认为可以删除最后一个反斜杠,因为@ 并且您不需要逃避正则表达式中的双引号,就像您已经在括号前没有做。
【解决方案2】:

更新

对于那些询问为什么不使用 String.Substring 的人:正则表达式相对于字符串操作的最大优势在于它们不会生成临时字符串,直到您真正要求匹配的值。匹配项和组仅包含源字符串的索引。这在处理日志文件时是一个巨大的优势。


您可以使用像

这样的正则表达式来匹配标签的内容
Tag\s*=\s*"(<tagValue>.*?)"

.*? 中的? 导致非贪婪搜索,即只提取到 first 双引号的文本。否则,该模式将匹配直到最后一个双引号的所有内容。

(&lt;tagValue&gt;.*?) 定义了一个命名组。这样你就可以引用 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 并行匹配多行。

【讨论】:

  • 您是否认为Regex 和LINQ 在幕后所做的一切都比生成一个额外的临时字符串?此外,代码可读性非常重要,老实说,我认为所有这些选项只会掩盖一个人的意图。
  • @Andrew 正如我解释的那样,不,它没有。它仅生成最终值,并且仅在请求时生成。 Substring 如果每行有两个或更多标签甚至是额外的空间,甚至都不会工作。您需要多个字符串拆分。至于可读性,各种选项确切地揭示了它们的意图 - 选择标记值,或标记和名称值。这更多是关于熟悉度而不是可读性。
  • 好吧,OP 没有指定该文件中可以或不可以包含哪些其他内容,所以我认为格式是他发布的。如果格式改变了,你的正则表达式也可能不起作用,所以我认为讨论没有意义。无论如何,我坚持:看看你的代码,你担心生成一个字符串,但使用所有的 LINQ。而且您假设 OP 需要List&lt;string&gt;,但情况可能并非如此。不要误会我的意思:您的代码很好,但我发现在这里担心字符串是不合逻辑的。只有当文件有 100K+ 行时,子字符串选项才可能使用更多资源。
【解决方案3】:

如果这些字符串总是是这样的,您可以通过使用Substring 来采用更简单的方法:

line.Substring(7, line.Length - 8)

这将为您提供所需的输出。

【讨论】:

    猜你喜欢
    • 2013-10-17
    • 1970-01-01
    • 1970-01-01
    • 2012-04-20
    • 1970-01-01
    • 1970-01-01
    • 2013-12-29
    • 2018-03-27
    • 2011-10-30
    相关资源
    最近更新 更多