如何用Python正则表达式解析与分词钻孔机器人指令文件?
用Python正则处理带递归多行REPEAT指令的钻孔机器人指令解析方案
针对你需要解析带递归嵌套、跨多行REPEAT指令的钻孔机器人指令集问题,以下是基于Python正则的具体实现方案:
核心思路:递归正则匹配嵌套结构
Python的re模块支持递归正则表达式(通过命名组引用(?&group_name)实现),可以直接处理REPEAT指令的嵌套需求。我们先定义基础指令的匹配规则,再递归匹配REPEAT块内的任意指令(包括嵌套的REPEAT)。
1. 正则模式定义
import re # 正则模式:匹配所有合法指令,支持递归嵌套REPEAT # 使用re.VERBOSE提高可读性,re.MULTILINE适配多行内容 cmd_pattern = re.compile(r''' (?P<instruction> # 旋转指令 (ROTATE (LEFT|RIGHT)) # 移动指令:N为自然数(从1开始) | (GO ([1-9]\d*) UNITS) # 钻孔指令 | DRILL # 递归REPEAT指令:匹配{...}内的所有指令(含嵌套REPEAT) | REPEAT ([1-9]\d*) TIMES \s* { \s* (?P<block>(?:(?&instruction)\s*)*) \s* } ) # 匹配指令间的任意空白(空格、换行、制表符) \s* ''', re.VERBOSE | re.MULTILINE)
2. 行号追踪与指令解析
要准确定位语法错误的行号,需要先读取整个文件内容,通过匹配位置计算对应的行号。同时遍历所有匹配结果,检查未匹配的内容以识别语法错误:
def parse_commands(file_path): with open(file_path, 'r', encoding='utf-8') as f: content = f.read() last_match_end = 0 # 遍历所有合法指令匹配 for match in cmd_pattern.finditer(content): # 计算当前指令的行号 current_line = content[:match.start()].count('\n') + 1 # 检查匹配前的未解析内容(语法错误) if match.start() > last_match_end: invalid_content = content[last_match_end:match.start()].strip() if invalid_content: print(f"语法错误:第{current_line}行,无效指令片段 '{invalid_content}'") # 提取指令类型并执行对应逻辑 full_cmd = match.group('instruction') if full_cmd.startswith('ROTATE'): direction = match.group(2) print(f"第{current_line}行:执行旋转{direction}") # 调用机器人旋转方法:robot.rotate(direction) elif full_cmd.startswith('GO'): units = int(match.group(5)) print(f"第{current_line}行:移动{units}单位") # 调用机器人移动方法:robot.go(units) elif full_cmd == 'DRILL': print(f"第{current_line}行:执行钻孔") # 调用机器人钻孔方法:robot.drill() elif full_cmd.startswith('REPEAT'): repeat_times = int(match.group(6)) block_content = match.group('block') print(f"第{current_line}行:重复{repeat_times}次执行块内容") # 递归处理REPEAT块内的指令 process_repeat_block(block_content, current_line) last_match_end = match.end() # 检查文件末尾的未解析内容 if last_match_end < len(content): error_line = content[:last_match_end].count('\n') + 1 invalid_content = content[last_match_end:].strip() if invalid_content: print(f"语法错误:第{error_line}行,无效指令片段 '{invalid_content}'") def process_repeat_block(block_content, start_line): """递归处理REPEAT块内的指令,计算块内指令的实际行号""" for match in cmd_pattern.finditer(block_content): # 计算块内指令相对于起始行的行号 relative_lines = block_content[:match.start()].count('\n') current_line = start_line + relative_lines full_cmd = match.group('instruction') if full_cmd.startswith('ROTATE'): direction = match.group(2) print(f"第{current_line}行(重复执行):旋转{direction}") # robot.rotate(direction) elif full_cmd.startswith('GO'): units = int(match.group(5)) print(f"第{current_line}行(重复执行):移动{units}单位") # robot.go(units) elif full_cmd == 'DRILL': print(f"第{current_line}行(重复执行):钻孔") # robot.drill() elif full_cmd.startswith('REPEAT'): repeat_times = int(match.group(6)) nested_block = match.group('block') print(f"第{current_line}行(重复执行):嵌套重复{repeat_times}次") # 递归处理嵌套REPEAT process_repeat_block(nested_block, current_line)
3. 关键注意事项
- 自然数匹配:正则中用
[1-9]\d*确保N是大于0的自然数,若允许0可改为\d+。 - 空白处理:所有指令间的分隔用
\s*,兼容单行多指令、跨多行指令的场景。 - 递归深度限制:Python正则的递归深度有限(默认约100层),若你的指令嵌套层数极深,可能需要改用PEG解析器(如
parsimonious),但常规场景下递归正则足够用。 - 语法错误定位:通过检查未匹配的内容,能精准定位无效指令的行号,满足需求。
内容的提问来源于stack exchange,提问作者Iosiv
相关产品推荐
相关产品推荐

