6

我正在做一个词法分析器作为大学课程的一部分。我们的教授给我们的脑筋急转弯(对得分没有贡献的额外作业)之一是我们如何在字符串文字中实现注释。

我们的字符串文字以感叹号开头和结尾。例如!this is a string literal!

我们的评论以三个句点开始和结束。例如...This is a comment...

从字符串文字中删除注释相对简单。只需通过匹配字符串文字/!.*!/并通过正则表达式删除注释。如果连续的逗号超过三个,但没有结束逗号,则抛出错误。

但是,我想更进一步。我想在字符串文字中实现感叹号的转义。不幸的是,我似乎无法让评论和感叹号转义符一起工作。

我想要创建的是可以包含注释和感叹号转义的字符串文字。怎么可能做到这一点?

例子:

!Normal string!
!String with escaped \! exclamation mark!
!String with a comment ... comment ...!
!String \! with both ... comments can have unescaped exclamation marks!!!... !

这是我当前的代码,不能忽略注释中的感叹号:

def t_STRING_LITERAL(t):
    r'![^!\\]*(?:\\.[^!\\]*)*!'
    # remove the escape characters from the string
    t.value = re.sub(r'\\!', "!", t.value)
    # remove single line comments
    t.value = re.sub(r'\.\.\.[^\r\n]*\.\.\.', "", t.value)
    return t
4

2 回答 2

2

也许这可能是另一种选择。

使用第一个否定字符类匹配除反斜杠、点或感叹号以外的任何字符 0+ 次。

然后,当您匹配第一个字符类不匹配的字符时,请使用交替匹配:

  • 重复 0+ 次,匹配一个不直接跟随 2 个点的点
  • 或从 3 个点匹配到下一个第一个 3 个点匹配
  • 或仅匹配转义字符

为了防止灾难性的回溯,您可以在 Python 中使用带有捕获组的正向前瞻来模拟原子组。如果断言为真,则使用反向引用\1来匹配。

例如

(?<!\\)![^!\\.]*(?:(?:\.(?!\.\.)|(?=(\.{3}.*?\.{3}))\1|\\.)[^!\\.]*)*!

解释

  • (?<!\\)!匹配 !没有直接在前面\
  • [^!\\.]*匹配任何字符的 1 次以上,除了! \or.
  • (?:非捕获组
    • (?:\.(?!\.\.)匹配一个不直接跟随 2 个点的点
    • |或者
    • (?=(\.{3}.*?\.{3}))\1...从最近的第 1 组断言和捕获...
    • |或者
    • \\.匹配转义字符
  • )关闭组
  • [^!\\.]*匹配任何字符的 1 次以上,除了! \or.
  • )*!关闭非捕获组并重复 0+ 次,然后匹配!

正则表达式演示

于 2020-10-05T18:21:19.987 回答
1

查看此正则表达式以匹配字符串文字:https ://regex101.com/r/v2bjWi/2 。 (?<!\\)!(?:\\!|(?:\.\.\.(?P<comment>.*?)\.\.\.)|[^!])*?(?<!\\)!.

  • 它被两个(?<!\\)!含义未转义的感叹号包围,
  • 它由交替转义的感叹号\\!、评论(?:\.\.\.(?P<comment>.*?)\.\.\.)和非感叹号组成[^!]。请注意,这与使用正则表达式所能达到的效果差不多。任何额外的要求,这将是不够的。
于 2020-10-05T15:20:23.143 回答