是否使用正则表达式来构建解析器?

时间:2010-08-15 11:04:28

标签: regex parsing

这只是一个出于好奇的问题,因为我最近需要越来越多地进行解析和使用正则表达式..似乎,对于我在搜索中遇到的关于某种解析的问题,有人总是会结束当被问及与正则表达式有关的事情时,“正则表达式对此并不好,请使用这样的解析器”......因为我已经更好地理解正则表达式,我认为大多数东西是可能的,只是它相当复杂和时间消费,因为你必须考虑到许多不同的可能性,当然,它必须与条件语句和循环组合以构建任何类型的解析器..所以我想知道正则表达式是用于构建大多数解析器或是还有其他方法正在使用..我只是想知道,因为我可能需要构建一些相当复杂的自定义解析器,而不一定要使用现有的解析器。

感谢任何信息,因为我似乎无法找到对此的直接答案。

8 个答案:

答案 0 :(得分:6)

不,解析器是从grammars构建的。

但是大多数编译器(解释器)将使用单独的扫描仪(词法分析器)来识别输入令牌。可以使用正则表达式指定扫描程序,但是它们不是使用通常的RegEx库类构建的。

单独的扫描仪是一种实用的方法。可以将完整的语法定义到字符级别,但这是不切实际的。正则表达式更容易处理语法的端点子集。

供参考,请参阅Yacc and Lex。他们都有现代接班人。

答案 1 :(得分:6)

通常,您将使用两种(至少)类型的工具来构建解析器。

第一部分是词法分析 - 将字符分成标记并过滤出注释和空格。该部分通常使用正则表达式完成。嗯,通常使用扫描仪生成器来完成,该生成器将正则表达式和代码对的集合转换为在识别正则表达式时执行相应代码的程序。这比每次测试每个正则表达式更有效,并且由于各种其他原因它也更好。 FLEX是C中的常用工具。

解析器的第二部分是语法。最典型的工具是另一个程序生成器,它接受一个无上下文语法(CFG)注释用于解释组件“词性”的规则,就像它一样。 CFG能够表达平衡括号之类的东西,正则表达式不能(除非它已经扩展了CF特征,使其在数学意义上不是严格的“常规”)。但是带有规则的CFG非常好,因为您可以在语言的短语结构中附加语义含义。 BISON是C部分的常用工具。

但我实际上告诉了你一个小谎言。您可以看到,每种真正的编程语言都有一些无法在无上下文框架中表达的部分。例如,您需要使用它来连接变量的定义,以便您知道要生成的指令,以及对其进行的操作是否合法。这通常被认为不在解析的范围之内,但是存在诸如“属性语法”之类的东西,就像CFG扩展的功能一样,甚至可以使这些上下文依赖性更容易编码和使用。

现在,没有规则说你必须使用这些工具。许多简单的语法很容易用手写工具进行处理。例如,LISP的S表达式可以简单地扫描为:

如果以数字开头,请阅读一个数字。 如果以字母开头,请阅读符号。 如果是空格,请跳过它。 如果它是一个开放式的,那么跳过它,将这个例程递归一个值,并期待一个接近的paren。

嗯,字符串和你有什么更多的复杂功能,但这是基本的想法。解析FORTH甚至更简单,因为它不构建递归数据结构。

无论如何,这应该让你继续你的项目。

答案 2 :(得分:2)

你知道'正则表达式'是创建确定性有限自动机的特殊符号。 DFA是一个解析设备,因此regexp会进行解析。当您使用正则表达式匹配某些内容时,您正在解析字符串以使其与模式对齐。当你使用正则表达式将一些东西用括号括起来时,你正在解析。

DFA被正式定义为特定类别语言的解析器,称为“常规语言”(感谢Gumbo提醒我)。许多重要任务都不涉及常规语言。

因此,DFA不是解决许多解析问题的好方法。这里最着名的例子是XML和HTML。原因很多,但我会填写一个。这些东西基本上都是树形结构。要解析它们,程序必须在树下降时保持状态。 Regexps不这样做。

由语法定义的解析器(例如LR(k)和LL(k))这样做,自上而下的手工编码解析器就是这样做的。

有各种替代解析技术的书籍和书籍,通常用于解析像C ++或XML这样的东西。

答案 3 :(得分:2)

(大多数)解析器是为递归语言创建的,即。具有递归功能的语言。 RegExps无法处理递归,因此它们不用于解析器构造(没有额外的攻击和Perl Markdown)。但是,RegExps 用于开发词法分析器,因为它们使生活变得更加容易。

答案 4 :(得分:2)

好吧,构建解析器非常复杂,您可以使用正则表达式,但这不是您使用的唯一内容。我建议阅读Dragon Book

现在,在我看来,你应该使用解析器生成器,因为你可以从头开始,但它不简单也不快。一般来说,你必须考虑正则表达式和有限状态自动机进行词法分析;语法分析等无上下文语法,LL解析器,自下而上解析器和LR解析器......等等......

答案 5 :(得分:2)

正则表达式可用于解析某种语言(有限状态语言),但与其他形式相比,它们的功能有限,正如您所提到的,它们很快变得不合适且难以维护。

例如,不可能有一个正则表达式可以确保每个左括号都有一个匹配的右括号 - 这是大多数语言在其表达式语法中的含义。

正则表达式通常用于进行标记化,然后组合标记以创建所需的语法。

答案 6 :(得分:2)

正则表达式是在任意标记上定义的,但大多数程序员只在字符串的上下文中遇到它们,因此很容易相信它们只对字符串有用。

作为纯粹的功能,正则表达式(实际上是单个正则表达式)无法解析任何需要无上下文语法的语言。

使无上下文语法与正则表达式不同的是,您可以定义一组语言的子语法的大型命名“识别器”,它们可以递归地相互引用。这些规则 都可以仅限于以下简单形式:

 LHS =  RHS1 RHS2 ... RHSn ;

(所以称之为“Backus Naur形式”或BNF),其中每个LHS和RHSi都是langauge中的原始语言元素或非终结符。 (我构建了一个非常复杂的语言处理工具,它使用 这个表单;你需要更多规则,但它非常实用。)

但是大多数写语法的人都想要一种更具表现力的形式,因此使用“扩展的BNF”。如果你仔细研究这些EBNF,他们通常会做的是从正则表达式中添加想法(交替,kleene star / plus) 到BNF的形式主义。因此,您可以找到带有“*”和“+”的EBNF。

因此,接下来是EBNF本身,使用正则表达式的想法:

 EBNF = RULE+ ;
 RULE = IDENTIFIER '=' ALTERNATIVES ';' ;
 ALTERNATIVES = RHS ( '|' RHS )* ;
 RHS = ITEM* ;
 ITEM = IDENTIFIER | QUOTEDTOKEN | '(' ALTERNATIVES ')' | ITEM ( '*' | '+' ) ;

因此,正则表达式思想可用于表达语法。需要一个接受这种表示法的解析器生成器(包括你手工完成)从语法实例生成一个解析器。

答案 7 :(得分:1)

通常,您在词法分析器中使用某种模式匹配(不一定是正则表达式),将您的字符流转换为标记流,并让您的解析器查看这些标记而不是原始字符输入。

如果您希望制作自己的解析器,那么最好不要使用Bison之类的东西来帮助解决这个问题。