如何忽略字符串文字中的注释
How to ignore comments inside string literals
我正在学习词法分析器作为大学课程的一部分。我们的教授给我们的脑筋急转弯之一(不影响评分的额外作业)是我们如何在字符串文字中实现注释。
我们的字符串文字以感叹号开头和结尾。例如!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
查看此正则表达式以匹配字符串文字:https://regex101.com/r/v2bjWi/2。
(?<!\)!(?:\!|(?:\.\.\.(?P<comment>.*?)\.\.\.)|[^!])*?(?<!\)!
.
- 被两个
(?<!\)!
包围,表示未转义的感叹号,
- 它由交替转义的感叹号
\!
、注释 (?:\.\.\.(?P<comment>.*?)\.\.\.)
和 non-exclamation 标记 [^!]
组成。
请注意,这与使用正则表达式所能达到的差不多。任何额外的要求,将不再足够。
也许这是另一种选择。
使用第一个否定字符匹配 0+ 次除反斜杠、点或感叹号之外的任何字符 class。
然后当你匹配第一个字符 class 不匹配的字符时,使用交替匹配:
- 重复 0 次以上,匹配一个没有直接跟随 2 个点的点
- 或从 3 个点匹配到下一个第一个匹配的 3 个点
- 或者只匹配一个转义字符
为了防止灾难性的回溯,您可以在 Python 中使用带有捕获组的正先行来模拟原子组。如果断言为真,则使用对</code>的反向引用来匹配</p>
<p>例如</p>
<pre><code>(?<!\)![^!\.]*(?:(?:\.(?!\.\.)|(?=(\.{3}.*?\.{3}))|\.)[^!\.]*)*!
说明
(?<!\)!
匹配!前面没有直接 \
[^!\.]*
匹配任何字符 1+ 次,除了 !
\
或 .
(?:
非捕获组
(?:\.(?!\.\.)
匹配一个点后不直接跟着 2 个点
|
或
(?=(\.{3}.*?\.{3}))
在组 1 中断言并捕获从 ...
到最近的 ...
|
或
\.
匹配转义字符
)
关闭群组
[^!\.]*
匹配任何字符 1+ 次,除了 !
\
或 .
)*!
关闭非捕获组重复0+次,然后匹配!
我正在学习词法分析器作为大学课程的一部分。我们的教授给我们的脑筋急转弯之一(不影响评分的额外作业)是我们如何在字符串文字中实现注释。
我们的字符串文字以感叹号开头和结尾。例如!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
查看此正则表达式以匹配字符串文字:https://regex101.com/r/v2bjWi/2。
(?<!\)!(?:\!|(?:\.\.\.(?P<comment>.*?)\.\.\.)|[^!])*?(?<!\)!
.
- 被两个
(?<!\)!
包围,表示未转义的感叹号, - 它由交替转义的感叹号
\!
、注释(?:\.\.\.(?P<comment>.*?)\.\.\.)
和 non-exclamation 标记[^!]
组成。 请注意,这与使用正则表达式所能达到的差不多。任何额外的要求,将不再足够。
也许这是另一种选择。
使用第一个否定字符匹配 0+ 次除反斜杠、点或感叹号之外的任何字符 class。
然后当你匹配第一个字符 class 不匹配的字符时,使用交替匹配:
- 重复 0 次以上,匹配一个没有直接跟随 2 个点的点
- 或从 3 个点匹配到下一个第一个匹配的 3 个点
- 或者只匹配一个转义字符
为了防止灾难性的回溯,您可以在 Python 中使用带有捕获组的正先行来模拟原子组。如果断言为真,则使用对</code>的反向引用来匹配</p>
<p>例如</p>
<pre><code>(?<!\)![^!\.]*(?:(?:\.(?!\.\.)|(?=(\.{3}.*?\.{3}))|\.)[^!\.]*)*!
说明
(?<!\)!
匹配!前面没有直接\
[^!\.]*
匹配任何字符 1+ 次,除了!
\
或.
(?:
非捕获组(?:\.(?!\.\.)
匹配一个点后不直接跟着 2 个点|
或(?=(\.{3}.*?\.{3}))
在组 1 中断言并捕获从...
到最近的...
|
或\.
匹配转义字符
)
关闭群组[^!\.]*
匹配任何字符 1+ 次,除了!
\
或.
)*!
关闭非捕获组重复0+次,然后匹配!