我的主要准则是在编写临时代码和用户输入验证时使用正则表达式。或者当我试图在一大段文本中查找特定模式的时候。对于其他大多数目的,我会编写语法并实现简单的解析器。
一个重要的准则(虽然我看到很多人尝试规避它)是在目标语言的语法是递归的情况下,总是使用解析器。
例如,考虑一个用于评估带括号算术表达式的小型“表达式语言”。这种语言中的“程序”示例如下:
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"))
if (str.contains("destroy the earth"))
if (str.indexOf(";") < str.length / 2)
一旦你的条件包含多个谓词,那么你就开始发明自己的临时字符串验证语言,你可能应该勇敢地学习一些正则表达式。
if (str.startsWith("I") && str.endsWith("Widget") &&
(!str.contains("Monkey") || !str.contains("Pox"))) // Madness.
正则表达式其实并不难学习。与 C# 这样拥有数十个关键字、基础类型和运算符、以及成千上万个类的完整语言相比,正则表达式绝对是非常简单的。大多数正则表达式实现支持约十几个操作(多或少不等)。
以下是一个很好的参考资料:
http://www.regular-expressions.info/
顺带一提,如果你确实想要学习编写自己的解析器(使用 lex/yacc、ANTLR、JavaCC 或其他类似工具),那么学习正则表达式是一个很好的准备,因为解析器生成器工具使用了许多相同的原则。