【问题标题】:When is it best to use Regular Expressions over basic string splitting / substring'ing?什么时候最好使用正则表达式而不是基本的字符串拆分/子字符串?
【发布时间】:2010-09-26 08:20:59
【问题描述】:

每当出现我需要字符串的一部分、有关所述字符串的信息等情况时,我似乎都会定期选择使用字符串解析与正则表达式。

出现这种情况的原因是我们正在评估一个肥皂头的动作,在它已被解析为可通过 WCF 的 OperationContext 对象管理的东西,然后对此做出决定。现在,简单的解决方案似乎是基本的子字符串化以保持实现简单,但我的一部分想知道 RegEx 是否会更好或更健壮。我的另一部分想知道这是否就像在我们的特定场景中使用霰弹枪杀死苍蝇一样。

所以我不得不问,人们在尝试决定使用 RegEx 而不是典型的字符串解析时使用的典型阈值是多少。请注意,我在正则表达式方面不是很擅长,因此,我会尽量回避,除非避免引入比我需要的更多的复杂性是绝对重要的。

如果您无法通过我选择的缩写来判断,这是在 .NET 领域 (C#),但我相信这与问题没有太大关系。


编辑:根据我典型的 Raybell 魅力,我的问题似乎过于冗长或误导。我想道歉。我提供了一些背景信息,以帮助提供有关我在做什么的线索,而不是误导人们。

我基本上是在寻找关于何时使用子字符串及其变体而不是正则表达式的指南,反之亦然。虽然有些答案可能错过了这一点(同样是我的错),但我真的很感激他们并相应地投票了。

【问题讨论】:

  • 除非你另有说明,否则我认为这个问题回答了你所问的同一个问题:stackoverflow.com/questions/56342/…
  • 它与我想要的很接近。我进行了搜索,但从未找到任何我认为合适的东西,尽管这似乎和任何东西一样接近。
  • 我想我要问的是这个问题是否为您提供了您正在寻找的信息?
  • 有点意思,但我似乎在下面有更好的答案,可能很快就会接受。

标签: regex parsing string


【解决方案1】:

我的主要指导方针是对一次性代码和用户输入验证使用正则表达式。或者当我试图在一大堆文本中找到特定模式时。对于大多数其他目的,我将编写一个语法并实现一个简单的解析器。

一个重要的指导原则(这确实很难回避,尽管我看到人们一直在尝试)是在目标语言的语法是递归的情况下始终使用解析器。

例如,考虑一种用于计算带括号的算术表达式的小型“表达式语言”。这种语言的“程序”示例如下所示:

1 + 2
5 * (10 - 6)
((1 + 1) / (2 + 2)) / 3

语法很容易编写,看起来像这样:

DIGIT := ["0"-"9"]
NUMBER := (DIGIT)+
OPERATOR := ("+" | "-" | "*" | "/" )
EXPRESSION := (NUMBER | GROUP) (OPERATOR EXPRESSION)?
GROUP := "(" EXPRESSION ")"

使用该语法,您可以快速构建递归下降解析器。

等价的正则表达式真的很难写,因为正则表达式通常不能很好地支持递归。

另一个很好的例子是 JSON 摄取。我见过人们尝试使用正则表达式来使用 JSON,这太疯狂了。 JSON 对象是递归的,因此它们只是在乞求常规语法和递归下降解析器。


嗯嗯嗯……看了其他人的回答,我想我可能答错了。

我将其解释为“什么时候应该使用简单的正则表达式,而不是成熟的解析器?”而大多数人似乎将这个问题解释为“什么时候应该推出自己笨拙的逐个字符验证方案,而不是使用正则表达式?”

鉴于这种解释,我的答案是:从不。


好的....再编辑一次。

我对自己动手的计划稍微宽容一点。只是......不要称之为“解析”:o)

我认为一个好的经验法则是,如果您可以使用单个谓词实现所有逻辑,那么您应该只使用字符串匹配原语。像这样:

if (str.equals("DooWahDiddy")) // No problemo.

if (str.contains("destroy the earth")) // Okay.

if (str.indexOf(";") < str.length / 2) // Not bad.

一旦您的条件包含多个谓词,那么您就已经开始发明自己的临时字符串验证语言了,您可能应该好好学习一些正则表达式。

if (str.startsWith("I") && str.endsWith("Widget") &&
    (!str.contains("Monkey") || !str.contains("Pox")))  // Madness.

正则表达式真的不难学。与具有数十个关键字、原始类型和运算符的 C# 之类的功能齐全的语言以及具有数千个类的标准库相比,正则表达式绝对是非常简单的。大多数正则表达式实现支持大约十几个操作(给予或接受)。

这是一个很好的参考:

http://www.regular-expressions.info/

PS:作为奖励,如果您确实想学习编写自己的解析器(使用 lex/yacc、ANTLR、JavaCC 或其他类似工具),学习正则表达式是一个很好的选择准备工作,因为解析器生成器工具使用许多相同的原理。

【讨论】:

  • 我的印象是“基本字符串解析”暗示了 1 .indexOf() 和 2 .subString() 调用或类似的东西。对于如此复杂的事情,我肯定也会使用解析器路由。
  • 我不一定要逐个字符地进行验证。我只是想获取一个子字符串,然后对其采取行动。一般来说,我正在寻找选择子字符串而不是正则表达式的一般准则。我相信我的问题可能不是很清楚......
  • 所以,在所有这些中,跟进您最近的编辑,这基本上就是我想要的。谢谢!
  • 很高兴我能(最终)提供帮助!
  • 和你一起讨论“真正的解析器”——为什么人们如此害怕语法?
【解决方案2】:

正则表达式可以是

  • 更容易理解
  • 更清楚地表达意图
  • 短得多
  • 更容易更改/适应

在某些情况下,所有这些优点都可以通过使用正则表达式来实现,在其他情况下,只能实现一些(例如,正则表达式并不容易理解),而在其他情况下,正则表达式更难理解,混淆了意图,更长且难以改变。

我从正则表达式中获得的这些(可能还有其他)优势越多,我就越有可能使用它们。

可能的经验法则:如果对一些熟悉正则表达式的人来说理解正则表达式需要几分钟,那么你不想使用它(除非“正常”代码更加复杂;-)。

嗯...仍然没有简单的经验法则,抱歉。

【讨论】:

    【解决方案3】:

    [W]我们正在评估一个肥皂标题的 采取行动并做出决定

    切勿使用正则表达式或基本字符串解析来处理 XML。现在常用的每种语言都具有非常好的 XML 支持。 XML 是一个看似复杂的标准,您的代码不太可能是正确的,因为它可以正确解析所有格式正确的 XML 输入,即使这样,您也是在浪费时间,因为(如前所述)每种语言常见用法有 XML 支持。使用正则表达式解析XML是不专业的。

    要回答您的问题,通常应尽量减少使用正则表达式,因为它们的可读性不强。通常,您可以结合字符串解析和正则表达式(可能在一个循环中)来创建比单独的正则表达式更简单的解决方案。

    【讨论】:

    • 我在这里有点误导,我很抱歉。现实情况是,当我们对此进行处理时,它已经通过 OperationContext 为我们解析了。不过,我感谢您指出这一点!
    • 我已经稍微更新了这个问题以提高清晰度,但在我看来它仍然令人困惑。当我有更多时间时,我会重新制作它。我很抱歉。
    • 对不起。我可能本来可以更有礼貌,但这就是我每次看到它都会让我发疯的东西。
    • 哦,不用担心!我就在你身边。有适合工作的正确工具。我不需要重新创建轮子或解析器,因为它可能是。
    【解决方案4】:

    我同意 benjismith 的说法,但想稍微详细说明一下。对于非常简单的语法,基本的字符串解析可以很好地工作,但正则表达式也可以。我不会称他们为矫枉过正。如果它有效,它就有效 - 使用您认为最简单的方法。对于中等到中等的字符串解析,正则表达式通常是要走的路。

    一旦您开始发现自己需要定义语法,即复杂的字符串解析,请尽快返回使用某种有限状态机或类似的东西。正则表达式根本不能很好地扩展,松散地使用这个术语。它们变得复杂、难以解释,甚至无能为力。

    我见过至少一个项目,其中正则表达式的使用不断增长,很快他们在插入新功能时遇到了麻烦。当终于到了发布新的主要版本时,他们转储了所有的正则表达式并采用了语法分析器。

    【讨论】:

    • 在这里的一种情况下,我看到一个正则表达式实际上递归地循环使用正确的输入。尖峰服务器 CPU 并允许 DOS 发生。不用说,当我看到它们出于这个原因作为解决方案出现时,我非常谨慎。
    【解决方案5】:

    当您需要的转换不是基本的——但在概念上仍然很简单。

    如果你正在做一个直接的字符串替换,没有理由退出正则表达式,例如......它更容易使用 string.Replace

    另一方面,如果您不明确地写出来,一个包含许多条件或特殊情况的复杂规则需要超过 50 个字符的正则表达式可能会成为日后维护的噩梦

    【讨论】:

      【解决方案6】:

      我总是使用正则表达式,除非它是 非常 简单的东西,例如拆分逗号分隔的字符串。如果我认为字符串有可能有一天会变得更复杂,我可能会从正则表达式开始。

      我不同意正则表达式很难或复杂的观点。这是每个开发人员都应该学习和学习好的工具。它们有无数的用途,一旦学会,这正是你永远不必担心的事情。

      正则表达式很少过度使用 - 如果匹配很简单,那么正则表达式也是如此。

      【讨论】:

      • 考虑到引用规则,即使是 CSV 解析器编写起来也看似复杂。 (换行符和逗号都可以出现在单个字段中,只要该字段用引号引起来。)不要低估不起眼的 CSV!即使使用正则表达式,也很难正确解析:o)
      • 我说的是逗号分隔的字符串,而不是 CSV 文件。除了 CSV 文件的专用库或解析器外,我永远不会推荐任何东西。我实际上已经编写了一个 C++ CSV 解析器来处理上述所有问题,但我父亲是一名 DFA
      【解决方案7】:

      我认为知道何时使用正则表达式以及何时不使用的最简单方法是,当您的字符串搜索需要 IF/THEN 语句或类似这种或那种逻辑的任何东西时,那么您需要比简单的字符串比较更好的东西这就是正则表达式大放异彩的地方。

      【讨论】:

        猜你喜欢
        • 2010-10-16
        • 1970-01-01
        • 2014-08-20
        • 2017-02-23
        相关资源
        最近更新 更多