正则表达式-使用Python 3中的正则表达式制作令牌生成器

时间:2018-11-11 17:25:57

标签: python regex python-3.x

我一直在尝试使一种语言的标记器成为一种练习。 例如,我正在尝试标记以下代码

num vecsum(vec A)
{
num n;
n = (5 + 2);
return n;
}

我一直在尝试使用此正则表达式

re.findall("[\'\w\-]+",text)

但是我得到这样的输出:vecsum(vec

我想像这样得到它:[“ vecsum”,“(”,“ vec”]

我希望它理解,即使那里没有空格,它也应该拆分诸如“;”和“(”

1 个答案:

答案 0 :(得分:1)

标记类似C的语言需要的工作不仅仅是在空格上拆分(这是您现在正在做的事情)。

至少有 3种此类语言的令牌:

  • 单个字符令牌,例如();+=
  • 多字符令牌,标识符,关键字,数字。
  • 字符串;开头引号和匹配的结尾引号之间的所有内容(支持转义符,并在不同程度上支持可能包含换行符的特殊字符串)。

我在这里忽略了注释,这些注释定义为从开始序列到行尾(# ...// ...等),或者从开始序列到结束序列行数(/* .... */)。

您可以定义一个可以对前两种类型进行标记化的正则表达式,然后使用其输出来处理字符串(当您获得"标记时,查找下一个"标记而不使用{ {1}}标记放在最前面,然后将介于两者之间的所有内容(空格和全部)作为字符串)。

这样的令牌生成器至少需要两个组,用于单个字符和多字符令牌。多字符令牌是另一组选项:

\

我使用operators in C and C++ on Wikipedia作为指导,寻找要查找的单字符令牌。

对于您的示例输入,将产生:

r'(?:[\\(){}[\]=&|^+<>/*%;.\'"?!~-]|(?:\w+|\d+))'

如果您必须将多符号运算符解析为单个标记,则还必须将它们作为单独的模式包括在正则表达式中,例如

['num', 'vecsum', '(', 'vec', 'A', ')', '{', 'num', 'n', ';', 'n', '=', '(', '5', '+', '2', ')', ';', 'return', 'n', ';', '}']

,但是您到了一个成熟的标记器的一半,该标记器为每种类型的文字和关键字定义了模式,您也可以将这种巨大的正则表达式分解为这些组成部分。有关此类标记程序的示例,请参见Python tokenize module source codebuilds up a large regex from component parts生成类型化的令牌。

另一种选择是坚持使用超简单的两部分式令牌生成器正则表达式,并使用re.finditer()来确定上下文中令牌的决策。在字符串中的( r'(?:==|!=|>=|<=|&&|\|\||<<|>>|->|::|\+\+|--|+=|-=' r'|\*=|/=|%=|<<=|>>=|&=|\^=|\|=' r'|[\\(){}[\]=&|^+<>/*%;.\'"?!~-]|(?:\w+|\d+))' ) start位置,您可以检测到end之前直接是=,因此知道您有=比较运算符而不是两个作业。如果您想查看示例,以前我曾在用于SQLite全文本搜索查询语言的简单解析器中使用过此语言(在code for this answer中查找==方法)。