使用Pyparsing为上下文敏感元素编写语法规则

时间:2017-02-23 12:31:09

标签: python regex parsing context-free-grammar pyparsing

我正在尝试为一组句子编写语法,并使用Pyparsing来解析它。这些句子告诉我们在文本文件中搜索什么以及如何搜索,我需要将它们转换为相应的正则表达式搜索代码。但是,有一些元素并非真正没有上下文,因此,我发现很难为它们编写生产规则。基本上,我的目标是解析这些句子,然后为它们写正则表达式。

在这些句子中找到的一些上下文敏感元素的例子 -

  1. LINE_CONTAINS phrase1 BEFORE {phrase2 AND phrase3}表示行phrase1可以在phrase2phrase之前到达。同样适用于AFTER

  2. LINE_CONTAINS abc JOIN xyz表示搜索abc xyzabc-xyz以及abcxyz

  3. LINE_CONTAINS abcd AND xyzw表示该行应同时包含abcdxyzw
  4. 示例 - LINE_CONTAINS we transfected BEFORE {sirna} AND gene AND LINE_STARTSWITH Therefore

    这应该转换为re.search(r'(^!Therefore.*?we transfected.*?sirna)' and re.search(r'(gene))(我相信可以制作更好的正则表达式)

    我开始为句子写语法 -

    Beginner = LINE_CONTAINS|LINE_STARTSWITH|other line beginners...
    Phrase = word+
    sentence = Beginner + phrase + AND + Beginner + phrase
    

    这些图案/元素中的任何一个都可以在任何行中出现,也可以组合使用。像

    LINE_CONTAINS {x AND y} BEFORE {a letter AND b letter} AND zoo people AND LINE_STARTSWITH dfg

    所以我的问题是 -

    如何编写可以处理此类上下文敏感元素的语法规则,因为任何句子都可以使用它们(尽管大多数句子不会有多个,但仍然如此)。 我应该为多种句子编写规则,每种句子都包含这些不同类型的元素之一。或者我应该编写一个包含所有这些元素的规则并将它们作为可选项。

    我确实理解这些元素可能不完全是上下文相关的,但我的问题在于无法为BEFOREJOIN等元素编写独立的生产规则。我如何最好在生产规则中定义它们的功能?

    编辑 - 短语可以是多字

2 个答案:

答案 0 :(得分:2)

在我看来,这是一个非常简单的语法。我认为你是“过度思考”这个问题。

看看你的例子,我看到了:

a JOIN b
a BEFORE b

a AND b
a OR b

STARTSWITH a

这些只是运营商。一元运算符(STARTSWITH)类似于python中的~x-x。二元运算符(JOIN,BEFORE,AND,OR)与python中的x + yx in y类似。

我认为CONTAINS不是一个操作员,而是一个占位符。几乎除了STARTSWITH之外的所有内容都是隐式包含的。所以这有点像一元加运算符:定义,理解,允许,但没用。

无论如何,弄清楚运营商是什么(列表)。弄清楚它们是一元(startwith)还是二元(和)。然后弄清楚他们的precedenceassociativity是什么。

一旦你知道了这些信息,你就可以构建你的解析器:你将知道关键词,并知道如何在语法中安排关键词。

答案 1 :(得分:1)

对你的语法做一些猜测,这是一个粗略的刺。请注意我如何从短语表达式中单独定义行表达式:

LINE_CONTAINS transfected BEFORE {sirna} AND gene AND LINE_STARTSWITH Therefore
[[['LINE_CONTAINS', [[['transfected', 'BEFORE', 'sirna'], 'AND', 'gene']]], 'AND', ['LINE_STARTSWITH', ['Therefore']]]]
[0]:
  [['LINE_CONTAINS', [[['transfected', 'BEFORE', 'sirna'], 'AND', 'gene']]], 'AND', ['LINE_STARTSWITH', ['Therefore']]]
  [0]:
    ['LINE_CONTAINS', [[['transfected', 'BEFORE', 'sirna'], 'AND', 'gene']]]
    - line_directive: 'LINE_CONTAINS'
    - phrase: [[['transfected', 'BEFORE', 'sirna'], 'AND', 'gene']]
      [0]:
        [['transfected', 'BEFORE', 'sirna'], 'AND', 'gene']
        [0]:
          ['transfected', 'BEFORE', 'sirna']
        [1]:
          AND
        [2]:
          gene
  [1]:
    AND
  [2]:
    ['LINE_STARTSWITH', ['Therefore']]
    - line_directive: 'LINE_STARTSWITH'
    - phrase: ['Therefore']

将您的样本解析为:

phrase_word

{}以负向前瞻开头,以避免意外处理类似' LINE_STARTSWITH'作为短语。我还将引用的字符串添加为有效的短语单词,因为您永远不知道您的搜索何时必须实际包含字符串" LINE_STARTSWITH"。

您使用infixNotation进行短语表达式分组,lpar具有可选的rpar(参数,以覆盖)和{{的默认值1}}。

从这里,您可以查看其他infixNotation示例(例如,在pyparsing wiki示例页面上的SimpleBool.py),将其转换为相应的正则表达式生成代码。