【问题标题】:Regex to parse C# source code to find all strings正则表达式解析 C# 源代码以查找所有字符串
【发布时间】:2009-06-08 16:08:00
【问题描述】:

我很久以前就问过这个问题, 我希望我已经阅读了答案 When not to use Regex in C# (or Java, C++ etc) 第一!

我希望使用 Regex(正则表达式)来获取我的 C# 源代码中所有字符串的列表,包括其中嵌入了双引号的字符串。

这应该不难,但是在我花时间尝试构建正则表达式之前,有没有人已经有了“预装”的?

这并不像最初看起来那么容易,因为

  • “av\”d”
  • @”ab””cd”
  • @”ab”””
  • @”””ab”

【问题讨论】:

  • 您可能会发现这比您预期的要多一些(取决于您的需要)。例如:注释代码呢?如果要忽略 cmets 中的字符串,则必须注意“//”和“/*..*/”块(除非注释分隔符本身位于字符串文字中)等。
  • 还有多行 @-strings 没有“答案”句柄。正则表达式无法处理这个问题,你必须使用解析器。
  • 正如 jwz 的名言,“现在你有两个问题”。 -- regex.info/blog/2006-09-15/247 -- 一开始我不会使用正则表达式来解决这个问题;我会写一个分词器。
  • 叹息。不要尝试使用正则表达式来解析非常规语言。您展示的示例只是会妨碍您的一些事情。一般来说,编程语言是“嵌套的”或“凹凸不平的”,通过使用正则表达式,您尝试将它们视为“扁平”。打个比方,你可以尝试绕过颠簸,但不清楚这样的算法是否真的总能达到目标。
  • 因此,“这应该不难”显然是错误的。使用普通的或“真正的”正则表达式,这是无法做到的。现代“正则表达式”引擎具有扩展部分非常规域,但它们的使用并非微不足道。所以,“这应该是非常困难的”,确实。

标签: c# .net regex


【解决方案1】:

我将此作为我的答案发布,以便其他阅读问题的人脱颖而出。

正如我在对我的问题有帮助的 cmets 中指出的那样,很明显,正则表达式不是在 C# 代码中查找字符串的好工具。在我提醒自己正则表达式语法的时间里,我本可以编写一个简单的“解析器”。 –(解析器是一个过度声明,因为在 cmets 等中没有“,这是我正在处理的源代码。)

这似乎总结得很好:

Some people, when confronted with a problem, think “I know, I'll use regular expressions.” Now they have two problems.

但是,在它破坏我的代码之前,我将使用 Blixt 发布的正则表达式,但如果它给我带来问题,我不会在编写自己的解析器之前花费匹配时间尝试修复它。例如,作为 C# 字符串,它是

@"@Q(?:[^Q]+|QQ)*Q|Q(?:[^Q\\]+|\\.)*Q".Replace('Q', '\"')

更新,上面的正则表达式有问题,所以我只写了自己的解析器,包括编写单元测试花了大约2个小时来编写解析器。这比我花在网上寻找(和测试)预装正则表达式的时间要少得多。

我看到的问题是,我倾向于避免使用 Regex,只自己编写字符串处理代码,然后很多人声称我不使用 Regex 是在浪费客户的钱。但是,每当我尝试使用正则表达式时,看似简单的匹配模式就会很快变得更难匹配。 (我读过的关于在 .net 中使用 Regex 的在线文章中没有一个很好的说明,明确说明何时不使用 Regex。MSDN 文档也是如此)

让我们看看我们是否可以帮助解决这个问题,我刚刚创建了一个堆栈溢出问题“When not to use Regex

【讨论】:

  • 你应该分享你的解析器!我知道至少还有一个问题是有人在做类似的事情。
  • @Josh,我是有偿写它的,所以不能发布它——而且,除了使用它的代码库之外,在任何代码库上失败都是非常容易的。 (用于查找可能需要翻译的字符串)
【解决方案2】:

查找C风格字符串的正则表达式为:

"(?:[^"\\]+|\\.)*"

这不会考虑 cmets,因此最好的办法是先删除所有 cmets,使用以下正则表达式:

/\*(?s:(?!\*/).)*\*/|//.*

请注意,如果将上述正则表达式放在字符串中,则需要将所有反斜杠加倍并转义所有引用标记。

更新: 将 cmets 的正则表达式更改为对多行 cmets 使用 DOTALL 标志。

此外,您可能希望支持文字字符串,因此请使用它而不是其他字符串正则表达式:

@"(?:[^"]+|"")*"|"(?:[^"\\]+|\\.)*"

提醒:不要将 DOTALL 用作任何这些正则表达式的全局标志,因为它会破坏单行 cmets 和单行字符串(普通字符串是单行的,而文字字符串可以跨越多行。)

【讨论】:

  • 这个正则表达式没有考虑@"" 类型的字符串文字。
  • @"(?:[^"]+|"")*"|"(?:[^"\]+|\\.)*" 不是有效的 C# 字符串,并且作为它在正则表达式中没有 @ 我看不出它是如何考虑 @"" 类型字符串文字的
  • 啊,但你看,它不是 C# 字符串,它只是正则表达式,如上所述。作为 C# 字符串,它将是 "@\"(?:[^\"]+|\"\")*\"|\"(?:[^\"\\\]+|\\\\. )*\""
【解决方案3】:

通过www.regular-expressions.info

"[^"\\\r\n]*(?:\\.[^"\\\r\n]*)*" 匹配单行字符串,如果引号字符被反斜杠转义,则可以出现在该字符串中。虽然这个正则表达式可能看起来比它需要的更复杂,但它比简单的解决方案要快得多,如果双引号单独出现在某个地方而不是字符串的一部分,可能会导致大量回溯。 "[^"\\]*(?:\\.[^"\\]*)*" 允许字符串跨越多行。

【讨论】:

  • 这个正则表达式虽然没有考虑@"" 类型的字符串字面量
【解决方案4】:

我在自己的 C# 解析器中使用的 5 美分表达式:

普通字符串:

"((\")|[^"\]|\)"

逐字字符串:

@("[^"]*")+

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-24
    • 1970-01-01
    • 1970-01-01
    • 2021-01-19
    • 1970-01-01
    • 2011-12-17
    • 1970-01-01
    相关资源
    最近更新 更多