如何忽略字符串文字中的注释

问题描述

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

我们的字符串文字以感叹号开头和结尾。例如!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

解决方法

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

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

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

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

为防止灾难性的回溯,您可以使用内部包含捕获组的正向超前模拟Python中的原子组。如果断言为真,则使用对\1的后向引用进行匹配。

例如

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

说明

  • (?<!\\)!匹配!不直接在\
  • 之前
  • [^!\\.]*匹配除! \.
  • 以外的任意字符1倍以上
  • (?:非捕获组
    • (?:\.(?!\.\.)匹配一个不直接跟有2个点的点
    • |
    • (?=(\.{3}.*?\.{3}))\1断言并捕获第1组中从...到最近的...
    • 的人
  • |
  • \\.匹配一个转义的字符
  • )关闭群组
  • [^!\\.]*匹配除! \.
  • 以外的任意字符1倍以上
  • )*!关闭非捕获组并重复0次以上,然后匹配!
  • Regex demo

    ,

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

    • 它被两个(?<!\\)!包围,表示未转义的感叹号,
    • 它由交替的转义的感叹号\\!,注释(?:\.\.\.(?P<comment>.*?)\.\.\.)和非感叹号[^!]组成。 请注意,这与使用正则表达式可以实现的功能差不多。任何其他请求,将不再足够。