在Java中根据语法验证字符串

时间:2015-03-16 00:52:57

标签: java regex validation parsing

我正在研究一个辅助项目(尝试学习正则表达式并在解析方面做得更好)并尝试编写一个函数来验证字符串在特定语法下是否有效。语法如下:

statement -> delimeter token
delimeter -> / or -
token -> name ([check])* (delimeter token)?
check -> token
         @id="..."

我已经为上面的每一个(令牌除外)写出正则表达式,它们写在下面。但是,当我试图写出令牌正则表达式时,我意识到它依赖于它自己(递归)。我不太确定如何编写这个正则表达式,或者这是否是正确的方法,因为检查可能会非常深入。有没有更好的方法来验证字符串是否可以用语法表示或没有?如果没有,我如何使用正则表达式?

String delimeter = "/|-";
String name = "((?i)\\A[a-z][_a-z\\d\\-\\.]*){1}";
String checkToken = would just be equal to token;
String checkID = "(?i)\\A\\s*@id\\s*=\\s*\".*\"\\s*\\Z";

我使用String.matches调用来查看字符串是否与正则表达式匹配,现在只需检查较小的内容,例如名称是否正确。

3 个答案:

答案 0 :(得分:4)

您正在寻求更好地了解Chomsky hierarchy

层次结构的简单形式具有以下类型:

  1. 递归枚举图灵机匹配
  2. 上下文相关线性有界非确定性图灵机匹配
  3. 无上下文非确定性下推自动机匹配
  4. 常规有限状态自动机匹配

正则表达式是有限状态自动机的描述,它可以匹配常规语言。如果语言不规律,那么在尝试将非常规语言与正则表达式匹配时会冒summoning Tony the Pony的风险(这不是一件好事)。

用于匹配的给定工具可以匹配其级别或更高级别的任何语言。因此,非确定性下推自动机可以匹配无上下文语言和常规语言。但是有限状态自动机只能匹配常规语言。

通常,在编译器设计等中,词法分析器(使用常规语言)与解析器生成器配对,该生成器使用无上下文语言。这可以通过lexyacc,或者flex和bison的配对来看出。

Lex的语法与令牌相匹配,并将它们传递给yacc。在现代Java世界中,您可能希望查看antlr - 另一种语言识别工具来帮助您编写解析器。 JavaCC也会被推荐(另一种工具,有些人更喜欢,如果你打算沿着这条路走下去,你应该看看这两个工具)。 Lex&如果您想对它们进行比较,Yacc,Antlr和JavaCC是parser generators工具域的一部分。

我建议给Lex & Yacc Tutorial读一读。虽然,是的,对于你没有使用的lex和yacc,有一个关于它背后的理论的部分(lexing和parsing)。理解该理论将有助于您理解当前方法无效的原因。

答案 1 :(得分:1)

  

尝试编写一个函数,该函数将验证字符串在特定语法下是否有效

错误,解析器是执行此操作的函数。如果它解析,它是有效的。如果它出现语法错误,则不是。这是验证字符串,没有根据你的标题验证语法本身。

  

我已经为上面的每一个(令牌除外)写出了正则表达式,它们写在下面。但是,当我试图写出令牌正则表达式时,我意识到它依赖于它自己(递归)。我不太确定如何编写这个正则表达式,或者这是否是正确的方法,因为检查可能会非常深入。有没有更好的方法来验证字符串是否可以用语法表示或没有?如果没有,我如何使用正则表达式?

你没有。

您无法使用正则表达式解析递归语法。正则表达式用于表征词法分析器。 语法将是一个无上下文的语法,LL(1)或LR(1)。如果您不知道这些术语的含义,那么您需要做很多阅读。

答案 2 :(得分:1)

具有递归定义的语法通常不是常规的,因此无法使用正则表达式进行解析。

但是,在您的情况下,您似乎可以将语法转换为常规形式:

statement -> ( delimiter token )+
delimiter -> / or -
token -> name ([check])*
check -> token
         @id="..."