Python词法分析:按行输出分类Token的问题求助
解决词法分析的分类与顺序输出问题
看起来你在实现一个简单的词法分析器时遇到了顺序混乱、重复输出、跨行打印的问题,核心原因是你的代码没有保留原文本的token顺序,而是把所有同类别元素集中收集,同时打印逻辑没有针对单行处理。下面是完整的解决方案:
核心思路
要实现按原文本顺序输出每个token及其类别,我们需要:
- 逐行读取文本,只处理当前行的内容
- 按文本顺序逐个识别每个token(包括分隔符),同时记录其类别
- 对每个token仅处理一次,避免重复输出
完整代码实现
import re # 定义token分类函数:根据token内容判断所属词法类 def classify_token(token): # 标识符:字母开头,后续可跟字母/数字 if re.fullmatch(r'[a-zA-Z][a-zA-Z0-9]*', token): return 'identifiers' # 常量:整数、浮点数,支持科学计数法(可选) elif re.fullmatch(r'[-+]?\d+\.?\d*|\.\d+([eE][-+]?\d+)?', token): return 'constants' # 操作符:匹配你定义的=、+、/ elif token in ('=', '+', '/'): return 'operators' # 分隔符:空白字符(空格、换行等) elif re.fullmatch(r'\s+', token): return 'separators' # 未知类型(可选处理) else: return 'unknown' # 读取目标文本文件 with open('your_file.txt', 'r') as file: lines = file.readlines() # 逐行处理并按要求格式输出 for line_idx, line in enumerate(lines, start=1): print(f'Line {line_idx}:') # 用正则匹配当前行的所有token(按原顺序) token_matches = re.finditer( r'([a-zA-Z][a-zA-Z0-9]*|[-+]?\d+\.?\d*|\.\d+([eE][-+]?\d+)?|=|\+|/|\s+)', line ) output_segments = [] for match in token_matches: token = match.group(0) # 可选:跳过换行符(如果不需要输出换行符的话) if token == '\n': continue category = classify_token(token) # 按要求格式生成每个token的输出片段 output_segments.append(f"('{token}', {category})") # 拼接所有片段并打印 print(' '.join(output_segments)) print()
代码说明
- 分类函数
classify_token:清晰定义了每个词法类的判断规则,你可以根据需求轻松扩展(比如添加更多操作符或关键字) - 逐行处理:通过
readlines()读取所有行,再用enumerate跟踪行号,确保只处理当前行的内容 - 顺序匹配token:使用
re.finditer按文本顺序匹配所有token,完全保留原文本的元素顺序 - 避免重复输出:每个token仅被匹配和处理一次,不会出现重复添加的问题
针对你原代码问题的分析
- 顺序混乱:你之前把所有identifiers、operators等分别收集到独立列表,再合并,完全打乱了原文本的顺序,导致输出时先所有标识符,再操作符,不符合要求
- 重复输出:使用
extend添加元素时,若正则匹配逻辑有问题(比如重复匹配同一元素),会导致列表中出现重复项 - 跨行打印:你的打印逻辑遍历了所有行的tokens,所以每一行都会输出整个文件的所有元素,而不是当前行的内容
- 正则错误:原常量正则中包含多余空格(比如
[+-]? *(?:\d+),导致无法正确识别常量
测试输出
用你提供的文本内容测试,输出会完全符合你的要求:
Line 1: ('a273', identifiers) (' ', separators) ('=', operators) (' ', separators) ('4', constants) (' ', separators) ('+', operators) (' ', separators) ('1337', constants) Line 2: ('variable', identifiers) (' ', separators) ('=', operators) (' ', separators) ('50.123132123', constants) (' ', separators) ('+', operators) (' ', separators) ('3.123123132', constants) (' ', separators) ('/', operators) (' ', separators) ('23.121212', constants)
内容的提问来源于stack exchange,提问作者Marko Markusevic




