4. 解析G和M指令

任务目标

实现一个G代码解析器的核心函数,能够从一行G代码文本中正确提取G指令(如G0、G90)和M指令(如M3、M5),并返回结构化结果。解析需支持行号前缀(N10)、注释剥离、大小写不敏感,以及同一行内多条指令的提取。

实现方案

使用正则表达式匹配G/M后跟1~3位数字的模式,遍历所有匹配项。解析前先剥离分号后的注释,并统一转为大写。返回结果包含指令类型(G/M)、指令数字和原始匹配文本。

完整代码

import re

def parse_gcode_line(line: str) -> list[dict]:
    """
    解析单行G代码,提取所有G和M指令。
    返回示例: [{'type': 'G', 'code': 0, 'raw': 'G0'}, ...]
    """
    # 剥离分号注释并转为大写
    code_part = line.split(';')[0].strip().upper()
    if not code_part:
        return []

    # 匹配 G/M + 1~3位数字(不匹配G代码中可能出现的字母后缀如G0.1)
    pattern = r'\b([GM])(\d{1,3})\b'
    matches = re.findall(pattern, code_part)

    result = []
    for type_letter, num_str in matches:
        result.append({
            'type': type_letter,
            'code': int(num_str),
            'raw': f'{type_letter}{num_str}'
        })
    return result

# 最小验证入口
if __name__ == '__main__':
    test_lines = [
        "N10 G90 G0 X10 Y20 ; 快速定位",
        "g1 x5 y5",
        "M3 S1000",
        "N20 G91 G1 X-5 F100 M8",
        "G0X0Y0",          # 无空格边界
        "; 纯注释行",
        ""
    ]
    for line in test_lines:
        print(f"输入: {line!r}")
        print(f"输出: {parse_gcode_line(line)}\n")

运行与验证

运行方式:将代码保存为 gcode_parser.py,在终端执行 python gcode_parser.py。

预期输出(与代码逻辑严格对应):

输入: 'N10 G90 G0 X10 Y20 ; 快速定位'
输出: [{'type': 'G', 'code': 90, 'raw': 'G90'}, {'type': 'G', 'code': 0, 'raw': 'G0'}]

输入: 'g1 x5 y5'
输出: [{'type': 'G', 'code': 1, 'raw': 'G1'}]

输入: 'M3 S1000'
输出: [{'type': 'M', 'code': 3, 'raw': 'M3'}]

输入: 'N20 G91 G1 X-5 F100 M8'
输出: [{'type': 'G', 'code': 91, 'raw': 'G91'}, {'type': 'G', 'code': 1, 'raw': 'G1'}, {'type': 'M', 'code': 8, 'raw': 'M8'}]

输入: 'G0X0Y0'
输出: [{'type': 'G', 'code': 0, 'raw': 'G0'}]

输入: '; 纯注释行'
输出: []

输入: ''
输出: []

验证判定标准:运行后观察输出是否与上述预期一致。重点确认:①注释内容被正确剥离;②小写g/m被转为大写识别;③同一行多条指令全部提取;④无空格粘连写法(如G0X0)仍能正确匹配;⑤纯注释行和空行返回空列表。

边界说明

本解析器针对整数G/M指令设计,不处理带小数点的G代码(如G0.1)或带字母后缀的扩展指令(如G54.1)。如需支持这些格式,需扩展正则表达式,但不影响当前案例对基础G/M指令解析目标的完整覆盖。