Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何从正则表达式中排除某些可能性?_Python_Regex_Parsing_Regex Group_Lark Parser - Fatal编程技术网

Python 如何从正则表达式中排除某些可能性?

Python 如何从正则表达式中排除某些可能性?,python,regex,parsing,regex-group,lark-parser,Python,Regex,Parsing,Regex Group,Lark Parser,对于我正在创建的解析器,我使用以下正则表达式作为ID的定义: ID: /[a-z_][a-z0-9]*/i (对于不熟悉我使用的特定解析器语法的人来说,“I”标志只是表示不区分大小写。) 我还有很多关键词,比如: CALL_KW: "call" PRINT_KW: "print" 问题是,由于语法中存在一些歧义,有时关键字被视为ID,而我真的不希望它们被视为ID。所以我在考虑是否可以重写ID的正则表达式,使关键字完全不匹配。这可能吗 为了提供更多的上下文,我使用了Python的解析器库。Ea

对于我正在创建的解析器,我使用以下正则表达式作为ID的定义:

ID: /[a-z_][a-z0-9]*/i
(对于不熟悉我使用的特定解析器语法的人来说,“I”标志只是表示不区分大小写。)

我还有很多关键词,比如:

CALL_KW: "call"
PRINT_KW: "print"
问题是,由于语法中存在一些歧义,有时关键字被视为ID,而我真的不希望它们被视为ID。所以我在考虑是否可以重写ID的正则表达式,使关键字完全不匹配。这可能吗


为了提供更多的上下文,我使用了Python的解析器库。Earley parser Lark提供的(与dynamic lexer一起)在处理歧义语法方面非常灵活和强大,但它们有时会做这样奇怪的事情(而且是非确定性的!)。因此,我试图在这里给解析器一些帮助,使关键字永远不匹配ID规则。

我相信Lark使用普通Python正则表达式,因此您可以使用否定的前瞻断言来排除关键字。但您必须注意不要拒绝以关键字开头的名称:

ID: /(?!(else|call)\b)[a-z_][a-z0-9]*/i
这个正则表达式在Python3中当然有效:

>>> # Test with just the word
>>> for test_string in ["x", "xelse", "elsex", "else"]:
...   m = re.match(r"(?!(else|call)\b)[a-z_][a-z0-9]*", test_string)
...   if m: print("%s: Matched %s" % (test_string, m.group(0)))
...   else: print("%s: No match" % test_string)
... 
x: Matched x
xelse: Matched xelse
elsex: Matched elsex
else: No match

>>> # Test with the word as the first word in a string
... for test_string in [word + " and more stuff" for word in ["x", "xelse", "elsex", "else"]]:
...   m = re.match(r"(?!(else|call)\b)[a-z_][a-z0-9]*", test_string)
...   if m: print("%s: Matched %s" % (test_string, m.group(0)))
...   else: print("%s: No match" % test_string)
... 
x and more stuff: Matched x
xelse and more stuff: Matched xelse
elsex and more stuff: Matched elsex
else and more stuff: No match

有几种方法不将类似的值传递给ID

正则表达式1 例如,您可以在表达式中使用捕获组,例如:

正则表达式电路 这有助于可视化您的表达式:

正则表达式2 另一种方法是使用:,从右侧绑定表达式,然后可以使用:

或带有
i
标志的原始表达式:

([a-z0-9_]+):

如果愿意,您可以添加更多的边界。

不确定您所说的有时关键字被视为ID的意思,但您可以在模式的左侧和右侧设置边界。也许可以尝试使用单词边界
\b
来阻止ID成为更大单词的一部分,或者如果支持,则使用lookarounds。您是指语法分析器模式还是词法分析器模式?这些是lexer模式,显然解析器规则中存在边界。然而,语法是模棱两可的,而且有多种选择。例如,单行“else”可以解释为调用例程“else”或关键字else。我希望lexer永远不要决定例行调用,因为这是一个关键字。另外,我不能改变语言本身,也不能改变我解析和解释它的方式。难道你不能强迫Lark使用
lexer='standard'
生成一个非上下文的lexer,如图所示吗?或者你在语法的其他地方依赖这个特性吗?我可以使用一个不太智能的词法分析器,但是“n-1”将被解析为两个标记:“n”和“-1”。是的,我还依赖于动态解析器。我想您希望像往常一样将
n-1
解析为三个标记。传统的看法是,允许数字文字用符号字符进行标记实际上没有什么好处。总是认为<代码> -1 < /代码>是两个令牌总是更好的。您可以(并且应该)在解析之后进行常量折叠。本质上,如果
-1
-1
在模糊的上下文中在语法或语义上出现差异,这是令人惊讶的。什么是
\b
?有了它,这根本不起作用。没有它,“else”和“xelse”不匹配,这很好,但是“elsex”不匹配,而我需要它。@elektito:这是一个单词边界匹配。我不知道为什么它不起作用,但我会看看我回家后是否能弄明白。它应该可以解决“elsex”的问题。输入文本中是否需要这样做?因为,我无法控制它。@elektito:它匹配一个单词和一个非单词之间的边界,该边界的长度为零,但肯定是“文本中的某物”,因为它匹配文本的一个特征。也就是说,它匹配单词字符(
[a-zA-Z0-9!]
)和非单词字符(任何其他字符或字符串结尾)之间的边界。请参阅以获得更详细的解释。@elektito:正则表达式在Python中也确实有效,我无法帮助您解决在Lark中使用它时遇到的问题,除非您向我展示失败的代码。不幸的是,我认为我不理解您的方法。您能否提供一个正则表达式来匹配所有这些
[a-z][a-z0-9]*
匹配项,但不能提供一些关键字,如
call
print
(\w+):
([a-z0-9_]+):