我一直在尝试使一种语言的标记器成为一种练习。 例如,我正在尝试标记以下代码
num vecsum(vec A)
{
num n;
n = (5 + 2);
return n;
}
我一直在尝试使用此正则表达式
re.findall("[\'\w\-]+",text)
但是我得到这样的输出:vecsum(vec
我想像这样得到它:[“ vecsum”,“(”,“ vec”]
我希望它理解,即使那里没有空格,它也应该拆分诸如“;”和“(”
答案 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 code; builds up a large regex from component parts生成类型化的令牌。
另一种选择是坚持使用超简单的两部分式令牌生成器正则表达式,并使用re.finditer()
来确定上下文中令牌的决策。在字符串中的(
r'(?:==|!=|>=|<=|&&|\|\||<<|>>|->|::|\+\+|--|+=|-='
r'|\*=|/=|%=|<<=|>>=|&=|\^=|\|='
r'|[\\(){}[\]=&|^+<>/*%;.\'"?!~-]|(?:\w+|\d+))'
)
和start
位置,您可以检测到end
之前直接是=
,因此知道您有=
比较运算符而不是两个作业。如果您想查看示例,以前我曾在用于SQLite全文本搜索查询语言的简单解析器中使用过此语言(在code for this answer中查找==
方法)。