我有一个为文本的每一行调用的函数。
def tokenize_line(line: str, cmd = ''):
matches = re.finditer(Patterns.SUPPORTED_TOKENS, line)
tokens_found, not_found, start_idx = [], [], 0
print(matches)
for match in matches:
pass
# Rest of code
print(matches)
的结果类似于:<callable_iterator object at 0x0000021201445000>
但是,当我将迭代器转换为列表时:
matches = list(re.finditer(Patterns.SUPPORTED_TOKENS, line))
或者当我用
for
迭代时:
for match in matches:
print(match)
...Python 冻结了。
此问题的发生不一致。例如:
tokenize_line('$color AS $length') # Works fine
tokenize_line('FALSE + $length IS GT 7 + $length IS 4') # Freezes
因此,当将 callable_iterator 转换为列表或对其进行迭代时,就会出现问题。
这是我正在使用的模式(Patterns.SUPPORTED_TOKENS):
(°p\d+°|°a\d+°|°m\d+°)|((?<!\S)(?:!\'(?:\\.|[^\'\n\\])*\'|!"(?:\\.|[^\n"\\])*")(?!\S))|((?:\'(?:\\.|[^\'\n\\])*\'|"(?:\\.|[^\n"\\])*"))|((\{(.*)\}))|((?<!\S)([@$][\w]*(?:\.[\w]*)*)(?!\S))|((?<!\d)-?\d*\.?\d+)|(\*\*|[\+\-\*\(\)/%\^]|==|&&|\|\||!=|>=|<=|>|<|~~|!~~|::|!::)|([\:/])|(\b(?:AS|AND|AT|:|BETWEEN|BY|FROM|IN|INTO|ON|OF|OR|THAN|TO|USING|WITH)\b)|(\b[a-zA-Z_][a-zA-Z0-9_]* *((?:[^;()\'""]*|"(?:[^"\\]|\\.)*"|\'(?:[^\'\\]|\\.)*\'|\([^)]*\))*?;))|((\b(?:EMPTY|STRING|NUMBER|BOOL|ARRAY|MAP|TRUE|FALSE|NULL|UNKNOWN|DOTALL|IGNORECASE|MULTILINE|ARRAY_ARRAY|ARRAY_STRING|ARRAY_MAP|ARRAY_NUMBER|ARRAY_NULL|DOT|SPACE|NEWLINE|SEMICOLON|COLON|HASH|COMMA|TAB)\b)|(\b(?:IS NOT LT|IS NOT GT|IS NOT GEQ|IS NOT LEQ|IS NOT|IS LT|IS GT|IS GEQ|IS LEQ|IS|NOT IN|NOT|IN|HAS NOT|HAS|AND|OR)\b))
正则表达式模式解释:
自定义标记:匹配以特定字符开头并后跟数字的特定自定义标记。
带引号的字符串: 匹配单引号和双引号字符串,包括带有转义字符的字符串。 大括号内容:匹配大括号内的任何内容。
变量: 匹配以特定字符(如 @ 或 $)开头的变量,并且可以包含嵌套属性的点。
数字: 匹配整数和浮点数,包括负数。
运算符:匹配各种数学和逻辑运算符。 冒号和斜杠:匹配特定的标点字符,例如冒号和斜杠。
关键字: 匹配该语言中保留的某些关键字。 函数定义:匹配函数定义或类似结构,确保它们遵循特定的语法规则。
数据类型和修饰符: 匹配表示数据类型或修饰符的关键字。
逻辑运算符:匹配条件表达式中使用的复杂逻辑运算符。
示例:
import re
SUPPORTED_TOKENS = r'(°p\d+°|°a\d+°|°m\d+°)|((?<!\S)(?:!\'(?:\\.|[^\'\n\\])*\'|!"(?:\\.|[^\n"\\])*")(?!\S))|((?:\'(?:\\.|[^\'\n\\])*\'|"(?:\\.|[^\n"\\])*"))|((\{(.*)\}))|((?<!\S)([@$][\w]*(?:\.[\w]*)*)(?!\S))|((?<!\d)-?\d*\.?\d+)|(\*\*|[\+\-\*\(\)/%\^]|==|&&|\|\||!=|>=|<=|>|<|~~|!~~|::|!::)|([\:/])|(\b(?:AS|AND|AT|:|BETWEEN|BY|FROM|IN|INTO|ON|OF|OR|THAN|TO|USING|WITH)\b)|(\b[a-zA-Z_][a-zA-Z0-9_]* *((?:[^;()\'""]*|"(?:[^"\\]|\\.)*"|\'(?:[^\'\\]|\\.)*\'|\([^)]*\))*?;))|((\b(?:EMPTY|STRING|NUMBER|BOOL|ARRAY|MAP|TRUE|FALSE|NULL|UNKNOWN|DOTALL|IGNORECASE|MULTILINE|ARRAY_ARRAY|ARRAY_STRING|ARRAY_MAP|ARRAY_NUMBER|ARRAY_NULL|DOT|SPACE|NEWLINE|SEMICOLON|COLON|HASH|COMMA|TAB)\b)|(\b(?:IS NOT LT|IS NOT GT|IS NOT GEQ|IS NOT LEQ|IS NOT|IS LT|IS GT|IS GEQ|IS LEQ|IS|NOT IN|NOT|IN|HAS NOT|HAS|AND|OR)\b))'
def tokenize_line(line: str, cmd = ''):
if not line:
return [], []
matches = list(re.finditer(SUPPORTED_TOKENS, line))
print(list)
lines = [
'$color AS $length',
'EMPTY + $length IS GT 7 + $length IS 4'
]
for x in lines:
tokenize_line(x)
任何帮助理解为什么会发生这种情况以及如何解决它的帮助将不胜感激!
正如评论中所指出的,挂起是由灾难性回溯引起的,因为您将模式
[^;()\'""]*
包装在一个可以重复零到多次的组中,这与您的整个输入相匹配,然后通过 ;
,它与您的输入不匹配,因此正则表达式引擎回溯字符,仍然匹配 [^;()\'""]*
,并且对于外部 *
,内部模式也匹配剩余字符,直到匹配在以下位置再次失败;
。重复此过程,直到正则表达式引擎用尽所有可能的方法来对输入进行分区,这相当于快速失控的组合数量,因为输入中的每个位置都可以是分区,也可以不是分区。您可以通过从 2 ^ (<number of characters> + 1)
中删除内部量词来解决此问题:
(?![^;()\'""]*|...)*?
演示:https://regex101.com/r/MszbVf/1