引言
在现代数控加工领域,数控编程语言常常包含变量和表达式,这为参数化编程提供了极大的灵活性。然而,在实际加工过程中,通常需要将参数化程序转换为具体的数值程序。本文将详细介绍如何使用Python处理包含变量的数控代码文件,实现变量替换和代码简化。
问题分析
数控代码中的变量通常以@符号开头,如@1107、@1017等。这些变量可能用于表示刀具半径补偿、加工深度等参数。变量之间可能存在依赖关系,例如:
@1017:=0.6427876096865394×@1107@1017: = 0.6427876096865394 × @1107@1017:=0.6427876096865394×@1107
@1018:=−0.766044443118978×@1107@1018: = -0.766044443118978 × @1107@1018:=−0.766044443118978×@1107
@1144:=8.21951+@1017@1144: = 8.21951 + @1017@1144:=8.21951+@1017
@1145:=94.79563+@1018@1145: = 94.79563 + @1018@1145:=94.79563+@1018
程序执行时,需要根据给定的@1107值计算所有相关变量,并将所有变量引用替换为具体数值,最终生成可直接执行的G代码。
解决方案设计
1. 基本思路
处理这类问题的核心思想是:
- 解析数控代码文件,识别变量赋值语句和变量引用
- 建立变量间的依赖关系,按顺序计算变量值
- 将代码中的变量引用替换为计算后的数值
- 清理变量赋值语句,生成简洁的G代码
2. 关键技术点
- 变量识别:使用正则表达式匹配变量格式
- 表达式计算:安全地计算包含变量的数学表达式
- 依赖关系处理:确保变量按正确顺序计算
- 代码简化:移除冗余的变量赋值语句
完整代码实现
版本1:基础处理框架
"""
数控代码变量替换处理框架
功能:读取包含变量的数控代码,替换所有变量为具体数值
作者:数控编程助手
版本:1.0
"""
import re
import os
class NcVariableProcessor:
"""数控代码变量处理器"""
def __init__(self):
"""初始化处理器"""
self.variables = {} # 存储变量值的字典
self.assignment_pattern = re.compile(r'@(\d+):\s*=\s*(.+);') # 匹配变量赋值
self.var_ref_pattern = re.compile(r'@(\d+)') # 匹配变量引用
def set_variable(self, var_name, value):
"""设置变量值
Args:
var_name: 变量名(不带@符号)
value: 变量值
"""
self.variables[str(var_name)] = float(value)
def compute_expression(self, expression):
"""计算数学表达式
Args:
expression: 包含变量引用的表达式字符串
Returns:
float: 计算结果
"""
# 替换表达式中的变量引用
def replace_var(match):
var_name = match.group(1)
if var_name in self.variables:
return str(self.variables[var_name])
else:
raise ValueError(f"未定义的变量: @{var_name}")
# 替换所有变量引用
expr = self.var_ref_pattern.sub(replace_var, expression)
try:
# 安全计算表达式
result = eval(expr, {"__builtins__": {}}, {})
return float(result)
except Exception as e:
raise ValueError(f"表达式计算错误: {expression} -> {e}")
def process_line(self, line):
"""处理单行代码
Args:
line: 输入行字符串
Returns:
tuple: (处理后的行, 是否输出该行)
"""
line = line.rstrip()
# 跳过空行和注释
if not line or line.startswith('%'):
return line, True
# 检查是否是变量赋值语句
match = self.assignment_pattern.match(line)
if match:
var_name = match.group(1)
expression = match.group(2)
try:
# 计算变量值
value = self.compute_expression(expression)
self.variables[var_name] = value
return None, False # 不输出赋值语句
except ValueError as e:
print(f"警告: {e}")
return line, True
# 处理非赋值语句,替换变量引用
def replace_in_code(match):
var_name = match.group(1)
if var_name in self.variables:
return f"{self.variables[var_name]:.5f}"
else:
return match.group(0) # 保持原样
processed_line = self.var_ref_pattern.sub(replace_in_code, line)
return processed_line, True
def process_file(self, input_file, output_file, initial_vars=None):
"""处理整个文件
Args:
input_file: 输入文件名
output_file: 输出文件名
initial_vars: 初始变量字典 {变量名: 值}
"""
# 初始化变量
if initial_vars:
for var_name, value in initial_vars.items():
self.set_variable(var_name, value)
# 读取文件
try:
with open(input_file, 'r', encoding='utf-8') as f:
lines = f.readlines()
except UnicodeDecodeError:
with open(input_file, 'r', encoding='gbk') as f:
lines = f.readlines()
# 处理每一行
processed_lines = []
for i, line in enumerate(lines, 1):
try:
processed_line, should_output = self.process_line(line)
if should_output and processed_line is not None:
processed_lines.append(processed_line)
except Exception as e:
print(f"第{i}行处理错误: {e}")
processed_lines.append(line) # 保持原行
# 写入输出文件
with open(output_file, 'w', encoding='utf-8') as f:
f.write('\n'.join(processed_lines))
print(f"处理完成: {input_file} -> {output_file}")
print(f"处理的变量数: {len(self.variables)}")
# 使用示例
if __name__ == "__main__":
# 创建处理器
processor = NcVariableProcessor()
# 设置初始变量(例如@1107的值)
processor.set_variable('1107', 10.0)
# 处理文件
input_file = "01001.txt"
output_file = "processed_nc.txt"
if os.path.exists(input_file):
processor.process_file(input_file, output_file)
# 显示变量计算结果
print("\n变量计算结果:")
for var_name, value in sorted(processor.variables.items()):
print(f" @{var_name} = {value:.10f}")
else:
print(f"文件不存在: {input_file}")
版本2:增强型变量处理器
"""
增强型数控代码变量处理器
功能:支持更复杂的表达式和批量处理
版本:2.0
"""
import re
import os
import math
class EnhancedNcProcessor:
"""增强型数控代码处理器"""
def __init__(self):
"""初始化处理器"""
self.variables = {}
self.lines_processed = 0
self.errors = []
# 编译正则表达式
self.assign_regex = re.compile(r'@(\d+):\s*=\s*(.+?)(?=;|$)')
self.var_regex = re.compile(r'@(\d+)')
# 支持的数学函数
self.safe_dict = {
'sin': math.sin, 'cos': math.cos, 'tan': math.tan,
'asin': math.asin, 'acos': math.acos, 'atan': math.atan,
'sqrt': math.sqrt, 'exp': math.exp, 'log': math.log,
'log10': math.log10, 'pi': math.pi, 'e': math.e,
'abs': abs, 'round': round, 'int': int, 'float': float
}
def add_variable(self, name, value):
"""添加或修改变量
Args:
name: 变量名
value: 变量值
"""
self.variables[str(name)] = float(value)
def evaluate_expression(self, expr):
"""安全地计算表达式
Args:
expr: 表达式字符串
Returns:
float: 计算结果
"""
# 替换变量引用
def replace_var(match):
var_name = match.group(1)
if var_name in self.variables:
return str(self.variables[var_name])
raise NameError(f"变量 @{var_name} 未定义")
# 替换所有变量引用
while True:
new_expr = self.var_regex.sub(replace_var, expr)
if new_expr == expr:
break
expr = new_expr
try:
# 安全计算
result = eval(expr, {"__builtins__": None}, self.safe_dict)
return float(result)
except Exception as e:
raise ValueError(f"表达式 '{expr}' 计算失败: {e}")
def parse_assignments(self, line):
"""解析行中的赋值语句
Args:
line: 输入行
Returns:
tuple: (非赋值部分, 赋值语句列表)
"""
assignments = []
remaining = line
# 查找所有赋值语句
pos = 0
while True:
match = self.assign_regex.search(remaining[pos:])
if not match:
break
# 提取赋值语句
full_match = match.group(0)
var_name = match.group(1)
expression = match.group(2).strip()
assignments.append((var_name, expression))
# 更新位置
pos += match.end()
# 如果后面是分号,跳过
if pos < len(remaining) and remaining[pos] == ';':
pos += 1
# 获取非赋值部分
non_assign = remaining[pos:] if pos < len(remaining) else ''
return non_assign.strip(), assignments
def process_single_line(self, line):
"""处理单行代码
Args:
line: 输入行
Returns:
str: 处理后的行
"""
self.lines_processed += 1
# 移除首尾空白
line = line.strip()
# 处理特殊行
if not line or line.startswith('%') or line.startswith('('):
return line
# 解析赋值语句
non_assign_part, assignments = self.parse_assignments(line)
# 处理赋值语句
for var_name, expression in assignments:
try:
value = self.evaluate_expression(expression)
self.add_variable(var_name, value)
except Exception as e:
self.errors.append(f"第{self.lines_processed}行: @{var_name}赋值失败 - {e}")
# 替换非赋值部分中的变量引用
def replace_vars_in_text(text):
def repl(match):
var_name = match.group(1)
if var_name in self.variables:
# 根据上下文决定精度
if 'G00' in text or 'G01' in text:
return f"{self.variables[var_name]:.5f}"
else:
return f"{self.variables[var_name]}"
return match.group(0)
return self.var_regex.sub(repl, text)
# 处理非赋值部分
processed_non_assign = replace_vars_in_text(non_assign_part)
# 清理多余的分号
if processed_non_assign.endswith(';'):
processed_non_assign = processed_non_assign.rstrip(';')
return processed_non_assign
def batch_process(self, input_files, output_dir, initial_vars=None):
"""批量处理多个文件
Args:
input_files: 输入文件列表
output_dir: 输出目录
initial_vars: 初始变量字典
"""
# 创建输出目录
os.makedirs(output_dir, exist_ok=True)
# 设置初始变量
if initial_vars:
for name, value in initial_vars.items():
self.add_variable(name, value)
results = []
for input_file in input_files:
if not os.path.exists(input_file):
print(f"警告: 文件不存在 {input_file}")
continue
# 重置处理器状态(保留初始变量)
current_vars = self.variables.copy()
self.variables = initial_vars.copy() if initial_vars else {}
self.errors = []
# 处理文件
output_file = os.path.join(output_dir, f"proc_{os.path.basename(input_file)}")
with open(input_file, 'r', encoding='utf-8') as f:
input_lines = f.readlines()
output_lines = []
for line in input_lines:
processed = self.process_single_line(line)
if processed: # 只添加非空行
output_lines.append(processed)
# 写入输出文件
with open(output_file, 'w', encoding='utf-8') as f:
f.write('\n'.join(output_lines))
# 恢复变量
self.variables = current_vars
# 记录结果
results.append({
'input': input_file,
'output': output_file,
'lines': len(output_lines),
'variables': len(self.variables),
'errors': self.errors.copy()
})
print(f"✓ 已处理: {input_file} -> {output_file}")
return results
# 使用示例
if __name__ == "__main__":
# 创建处理器
processor = EnhancedNcProcessor()
# 设置初始变量
initial_variables = {
'1107': 5.0, # 示例值
'1001': 10.0, # 可以设置多个初始变量
}
# 要处理的文件列表
input_files = ["01001.txt", "01002.txt"] # 假设有多个文件
# 批量处理
output_dir = "processed_files"
results = processor.batch_process(input_files, output_dir, initial_variables)
# 显示处理结果
print(f"\n处理完成!共处理 {len(results)} 个文件")
print(f"输出目录: {output_dir}")
# 显示汇总信息
total_errors = sum(len(r['errors']) for r in results)
if total_errors > 0:
print(f"\n发现 {total_errors} 个错误:")
for result in results:
for error in result['errors']:
print(f" {error}")
else:
print("\n所有文件处理成功,无错误!")
版本3:优化版G代码生成器
"""
优化版G代码生成器
功能:生成简洁、格式化的G代码
版本:3.0
"""
import re
import os
from datetime import datetime
class GCodeOptimizer:
"""G代码优化器"""
def __init__(self, precision=5):
"""初始化优化器
Args:
precision: 数值精度(小数位数)
"""
self.precision = precision
self.variables = {}
self.macro_definitions = {}
# 编译正则表达式
self.macro_pattern = re.compile(r'%\s*@MACRO\s*;', re.IGNORECASE)
self.assign_pattern = re.compile(r'@(\d+)\s*:\s*=\s*(.+?)\s*(;|$)')
self.var_pattern = re.compile(r'@(\d+)')
self.gcode_pattern = re.compile(r'([GXYZABCUF]\s*[-]?\d*\.?\d+)', re.IGNORECASE)
def set_variable(self, name, value):
"""设置变量值
Args:
name: 变量名
value: 变量值
"""
self.variables[str(name)] = float(value)
def format_number(self, number):
"""格式化数字
Args:
number: 输入数字
Returns:
str: 格式化后的字符串
"""
return f"{float(number):.{self.precision}f}".rstrip('0').rstrip('.')
def evaluate_expression(self, expression):
"""计算表达式
Args:
expression: 表达式字符串
Returns:
float: 计算结果
"""
# 替换变量引用
def replace_match(match):
var_name = match.group(1)
if var_name in self.variables:
return str(self.variables[var_name])
return match.group(0)
expr = self.var_pattern.sub(replace_match, expression)
try:
# 安全计算
result = eval(expr, {"__builtins__": {}}, {})
return float(result)
except Exception as e:
raise ValueError(f"表达式错误: {expression} -> {e}")
def parse_line(self, line):
"""解析行内容
Args:
line: 输入行
Returns:
dict: 解析结果
"""
line = line.strip()
result = {
'original': line,
'is_macro': False,
'is_comment': False,
'is_assignment': False,
'is_gcode': False,
'assignments': [],
'gcode_commands': [],
'processed': line
}
# 检查宏定义
if self.macro_pattern.match(line):
result['is_macro'] = True
result['processed'] = f"% MACRO PROCESSED AT {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
return result
# 检查注释
if line.startswith('%') or line.startswith('(') or line.startswith(';'):
result['is_comment'] = True
return result
# 检查赋值语句
assignments = []
remaining = line
# 查找所有赋值语句
while True:
match = self.assign_pattern.search(remaining)
if not match:
break
var_name = match.group(1)
expression = match.group(2)
assignments.append({
'var_name': var_name,
'expression': expression,
'full_match': match.group(0)
})
# 移除已匹配的部分
remaining = remaining[:match.start()] + remaining[match.end():]
if assignments:
result['is_assignment'] = True
result['assignments'] = assignments
# 检查G代码
gcode_matches = list(self.gcode_pattern.finditer(remaining))
if gcode_matches:
result['is_gcode'] = True
result['gcode_commands'] = [m.group(1) for m in gcode_matches]
# 处理剩余部分(可能包含变量引用)
if remaining.strip():
# 替换变量引用
def replace_vars(match):
var_name = match.group(1)
if var_name in self.variables:
return self.format_number(self.variables[var_name])
return match.group(0)
processed = self.var_pattern.sub(replace_vars, remaining)
result['processed'] = processed.strip()
return result
def optimize_gcode_block(self, commands):
"""优化G代码块
Args:
commands: G代码命令列表
Returns:
str: 优化后的G代码行
"""
if not commands:
return ""
# 按字母排序并合并
grouped = {}
for cmd in commands:
# 提取命令字母和值
letter = cmd[0].upper()
value = cmd[1:].strip()
# 保留原始值,格式化在最后进行
grouped[letter] = value
# 构建优化后的字符串
# G命令放在最前面
ordered_keys = []
if 'G' in grouped:
ordered_keys.append('G')
# 然后是运动坐标
for axis in ['X', 'Y', 'Z', 'A', 'B', 'C']:
if axis in grouped:
ordered_keys.append(axis)
# 最后是其他参数
for key in sorted(grouped.keys()):
if key not in ordered_keys:
ordered_keys.append(key)
# 生成优化后的命令
optimized_parts = []
for key in ordered_keys:
try:
value = float(grouped[key])
formatted = self.format_number(value)
optimized_parts.append(f"{key}{formatted}")
except:
optimized_parts.append(f"{key}{grouped[key]}")
return ' '.join(optimized_parts)
def process_file(self, input_file, output_file, initial_vars=None):
"""处理文件
Args:
input_file: 输入文件
output_file: 输出文件
initial_vars: 初始变量
"""
# 设置初始变量
if initial_vars:
for name, value in initial_vars.items():
self.set_variable(name, value)
# 读取文件
try:
with open(input_file, 'r', encoding='utf-8') as f:
lines = f.readlines()
except:
with open(input_file, 'r', encoding='gbk') as f:
lines = f.readlines()
# 处理每一行
processed_lines = []
line_stats = {
'total': 0,
'comments': 0,
'assignments': 0,
'gcode': 0,
'macros': 0,
'errors': 0
}
for line_num, line in enumerate(lines, 1):
line_stats['total'] += 1
try:
# 解析行
parsed = self.parse_line(line)
# 处理赋值语句
if parsed['is_assignment']:
line_stats['assignments'] += 1
for assign in parsed['assignments']:
try:
value = self.evaluate_expression(assign['expression'])
self.set_variable(assign['var_name'], value)
except Exception as e:
print(f"第{line_num}行警告: {e}")
line_stats['errors'] += 1
# 处理G代码
elif parsed['is_gcode']:
line_stats['gcode'] += 1
# 如果有G代码命令,进行优化
if parsed['gcode_commands']:
optimized = self.optimize_gcode_block(parsed['gcode_commands'])
# 如果有其他内容,添加到优化后的G代码后面
other_content = parsed['processed']
if other_content and not other_content.startswith(tuple('GXYZABC')):
if optimized:
processed_line = f"{optimized} ; {other_content}"
else:
processed_line = other_content
else:
processed_line = optimized if optimized else other_content
if processed_line:
processed_lines.append(processed_line)
# 处理宏和注释
elif parsed['is_macro']:
line_stats['macros'] += 1
processed_lines.append(parsed['processed'])
elif parsed['is_comment']:
line_stats['comments'] += 1
processed_lines.append(parsed['original'])
else:
# 其他内容
if parsed['processed']:
processed_lines.append(parsed['processed'])
except Exception as e:
print(f"第{line_num}行错误: {e}")
processed_lines.append(line) # 保持原行
line_stats['errors'] += 1
# 添加文件头注释
header = [
f"% Generated by GCodeOptimizer v3.0",
f"% Source: {os.path.basename(input_file)}",
f"% Processed: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
f"% Variables used: {len(self.variables)}",
f"% Precision: {self.precision} decimal places",
f"%"
]
# 写入输出文件
with open(output_file, 'w', encoding='utf-8') as f:
f.write('\n'.join(header + [''] + processed_lines))
# 显示统计信息
print(f"\n=== 处理统计 ===")
print(f"输入文件: {input_file}")
print(f"输出文件: {output_file}")
print(f"总行数: {line_stats['total']}")
print(f"G代码行: {line_stats['gcode']}")
print(f"赋值语句: {line_stats['assignments']}")
print(f"注释/宏: {line_stats['comments'] + line_stats['macros']}")
print(f"错误数: {line_stats['errors']}")
print(f"压缩率: {(1 - len(processed_lines)/line_stats['total'])*100:.1f}%")
return {
'stats': line_stats,
'variables': self.variables,
'output_file': output_file
}
# 使用示例
if __name__ == "__main__":
# 创建优化器
optimizer = GCodeOptimizer(precision=5)
# 设置初始变量
initial_vars = {'1107': 15.5} # 可根据需要修改
# 输入输出文件
input_file = "01001.txt"
output_file = "optimized_nc.txt"
if os.path.exists(input_file):
# 处理文件
result = optimizer.process_file(input_file, output_file, initial_vars)
# 显示变量值
print(f"\n=== 变量值 ===")
for var_name, value in sorted(result['variables'].items()):
print(f"@{var_name} = {value:.{optimizer.precision}f}")
# 显示输出文件前10行
print(f"\n=== 输出文件预览 ===")
with open(output_file, 'r') as f:
for i in range(10):
line = f.readline()
if not line:
break
print(line.rstrip())
else:
print(f"输入文件不存在: {input_file}")
版本4:完整应用示例
"""
数控代码批量处理工具
功能:完整的数控代码处理流水线
版本:4.0
"""
import os
import sys
import json
import logging
from datetime import datetime
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('nc_processor.log'),
logging.StreamHandler(sys.stdout)
]
)
class NcProcessingPipeline:
"""数控代码处理流水线"""
def __init__(self, config_file=None):
"""初始化流水线
Args:
config_file: 配置文件路径
"""
self.config = self.load_config(config_file)
self.processors = []
self.results = []
# 设置默认配置
self.default_config = {
'precision': 5,
'remove_comments': False,
'optimize_gcode': True,
'output_format': 'txt',
'backup_original': True,
'log_level': 'INFO'
}
if self.config:
self.default_config.update(self.config)
self.config = self.default_config
logging.info(f"数控代码处理流水线已初始化,配置: {self.config}")
def load_config(self, config_file):
"""加载配置文件
Args:
config_file: 配置文件路径
Returns:
dict: 配置字典
"""
if config_file and os.path.exists(config_file):
try:
with open(config_file, 'r') as f:
return json.load(f)
except Exception as e:
logging.error(f"配置文件加载失败: {e}")
return {}
return {}
def validate_input_file(self, file_path):
"""验证输入文件
Args:
file_path: 文件路径
Returns:
bool: 是否有效
"""
if not os.path.exists(file_path):
logging.error(f"文件不存在: {file_path}")
return False
if not file_path.lower().endswith(('.txt', '.nc', '.cnc')):
logging.warning(f"文件扩展名可能不受支持: {file_path}")
# 检查文件大小(不超过10MB)
if os.path.getsize(file_path) > 10 * 1024 * 1024:
logging.error(f"文件过大: {file_path}")
return False
return True
def parse_variable_assignments(self, content):
"""解析变量赋值语句
Args:
content: 文件内容
Returns:
dict: 变量依赖关系
"""
import re
# 匹配变量赋值
pattern = re.compile(r'@(\d+)\s*:\s*=\s*(.+?)(?=;|\n|$)')
assignments = {}
for match in pattern.finditer(content):
var_name = match.group(1)
expression = match.group(2).strip()
# 提取依赖的变量
deps = re.findall(r'@(\d+)', expression)
assignments[var_name] = {
'expression': expression,
'dependencies': list(set(deps)),
'computed': False,
'value': None
}
return assignments
def compute_variable_values(self, assignments, initial_values):
"""计算变量值
Args:
assignments: 变量赋值字典
initial_values: 初始变量值
Returns:
dict: 计算后的变量值
"""
import re
# 初始化变量值
computed = {}
computed.update(initial_values)
# 标记已计算的变量
for var_name in initial_values:
if var_name in assignments:
assignments[var_name]['computed'] = True
assignments[var_name]['value'] = initial_values[var_name]
# 计算顺序
max_iterations = len(assignments) * 2 # 防止无限循环
iteration = 0
while iteration < max_iterations:
iteration += 1
progress = False
for var_name, info in assignments.items():
if info['computed']:
continue
# 检查依赖是否都已计算
deps_computed = all(dep in computed for dep in info['dependencies'])
if deps_computed:
try:
# 替换表达式中的变量引用
expression = info['expression']
for dep in info['dependencies']:
expression = expression.replace(f'@{dep}', str(computed[dep]))
# 计算表达式
value = eval(expression, {"__builtins__": {}}, {})
computed[var_name] = float(value)
info['computed'] = True
info['value'] = value
progress = True
logging.debug(f"计算变量 @{var_name} = {expression} = {value}")
except Exception as e:
logging.error(f"变量 @{var_name} 计算失败: {e}")
# 使用默认值0
computed[var_name] = 0.0
info['computed'] = True
info['value'] = 0.0
progress = True
if not progress:
break
# 检查未计算的变量
for var_name, info in assignments.items():
if not info['computed']:
logging.warning(f"变量 @{var_name} 未计算,使用默认值0")
computed[var_name] = 0.0
return computed
def process_single_file(self, input_file, output_file=None, initial_values=None):
"""处理单个文件
Args:
input_file: 输入文件
output_file: 输出文件
initial_values: 初始变量值
Returns:
dict: 处理结果
"""
start_time = datetime.now()
# 验证文件
if not self.validate_input_file(input_file):
return {
'status': 'error',
'message': f'文件验证失败: {input_file}'
}
# 默认输出文件名
if not output_file:
base_name = os.path.splitext(os.path.basename(input_file))[0]
output_file = f"{base_name}_processed.{self.config['output_format']}"
# 备份原文件
if self.config['backup_original']:
backup_file = f"{input_file}.backup"
try:
import shutil
shutil.copy2(input_file, backup_file)
logging.info(f"已备份原文件: {backup_file}")
except Exception as e:
logging.warning(f"文件备份失败: {e}")
try:
# 读取文件
with open(input_file, 'r', encoding='utf-8') as f:
content = f.read()
# 解析变量赋值
assignments = self.parse_variable_assignments(content)
logging.info(f"解析到 {len(assignments)} 个变量赋值")
# 计算变量值
initial_values = initial_values or {}
computed_values = self.compute_variable_values(assignments, initial_values)
logging.info(f"计算了 {len(computed_values)} 个变量值")
# 替换变量引用
import re
var_pattern = re.compile(r'@(\d+)')
def replace_var(match):
var_name = match.group(1)
if var_name in computed_values:
value = computed_values[var_name]
# 根据精度格式化
return f"{value:.{self.config['precision']}f}"
return match.group(0)
# 替换所有变量引用
processed_content = var_pattern.sub(replace_var, content)
# 移除变量赋值语句(可选)
if self.config.get('remove_assignments', True):
assignment_pattern = re.compile(r'@\d+\s*:\s*=.*?(?=;|\n|$);?')
processed_content = assignment_pattern.sub('', processed_content)
# 移除注释(可选)
if self.config.get('remove_comments', False):
# 移除%注释
processed_content = re.sub(r'%.*?(?=\n|$)', '', processed_content)
# 移除()注释
processed_content = re.sub(r'\(.*?\)', '', processed_content)
# 优化G代码格式
if self.config.get('optimize_gcode', True):
# 合并多空格
processed_content = re.sub(r'\s+', ' ', processed_content)
# 清理多余的分号
processed_content = re.sub(r';\s*;', ';', processed_content)
# 移除空行
lines = processed_content.split('\n')
processed_lines = [line.strip() for line in lines if line.strip()]
processed_content = '\n'.join(processed_lines)
# 写入输出文件
with open(output_file, 'w', encoding='utf-8') as f:
f.write(processed_content)
# 计算处理时间
end_time = datetime.now()
duration = (end_time - start_time).total_seconds()
# 收集结果
result = {
'status': 'success',
'input_file': input_file,
'output_file': output_file,
'original_size': len(content),
'processed_size': len(processed_content),
'variables_found': len(assignments),
'variables_computed': len(computed_values),
'processing_time': duration,
'compression_ratio': (1 - len(processed_content)/len(content)) * 100,
'timestamp': end_time.isoformat()
}
logging.info(f"文件处理完成: {input_file} -> {output_file}")
logging.info(f"处理统计: {result}")
return result
except Exception as e:
logging.error(f"文件处理失败 {input_file}: {e}")
return {
'status': 'error',
'message': str(e),
'input_file': input_file
}
def process_batch(self, input_files, output_dir=None, initial_values=None):
"""批量处理文件
Args:
input_files: 输入文件列表
output_dir: 输出目录
initial_values: 初始变量值
Returns:
list: 处理结果列表
"""
results = []
# 创建输出目录
if output_dir:
os.makedirs(output_dir, exist_ok=True)
total_files = len(input_files)
successful = 0
failed = 0
logging.info(f"开始批量处理 {total_files} 个文件")
for i, input_file in enumerate(input_files, 1):
logging.info(f"处理文件 {i}/{total_files}: {input_file}")
# 确定输出文件路径
if output_dir:
base_name = os.path.basename(input_file)
output_file = os.path.join(output_dir, f"proc_{base_name}")
else:
output_file = None
# 处理文件
result = self.process_single_file(input_file, output_file, initial_values)
# 更新统计
if result['status'] == 'success':
successful += 1
else:
failed += 1
results.append(result)
# 显示进度
progress = (i / total_files) * 100
logging.info(f"进度: {progress:.1f}% | 成功: {successful} | 失败: {failed}")
# 生成汇总报告
summary = {
'total_files': total_files,
'successful': successful,
'failed': failed,
'success_rate': (successful / total_files * 100) if total_files > 0 else 0,
'total_processing_time': sum(r.get('processing_time', 0) for r in results if r['status'] == 'success'),
'average_compression': sum(r.get('compression_ratio', 0) for r in results if r['status'] == 'success') / successful if successful > 0 else 0,
'timestamp': datetime.now().isoformat()
}
logging.info(f"批量处理完成,汇总: {summary}")
# 保存结果到JSON文件
report_file = f"processing_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
with open(report_file, 'w') as f:
json.dump({
'config': self.config,
'summary': summary,
'results': results
}, f, indent=2)
logging.info(f"详细报告已保存到: {report_file}")
return results, summary
def generate_variable_report(self, input_file):
"""生成变量分析报告
Args:
input_file: 输入文件
Returns:
dict: 变量报告
"""
if not self.validate_input_file(input_file):
return None
try:
with open(input_file, 'r') as f:
content = f.read()
# 解析变量
assignments = self.parse_variable_assignments(content)
# 提取所有变量引用
import re
all_var_refs = re.findall(r'@(\d+)', content)
var_usage = {}
for var in set(all_var_refs):
var_usage[var] = all_var_refs.count(var)
# 分析变量类型
numeric_vars = []
expression_vars = []
for var_name, info in assignments.items():
if re.match(r'^[-+]?\d*\.?\d+$', info['expression'].strip()):
numeric_vars.append(var_name)
else:
expression_vars.append(var_name)
# 构建报告
report = {
'file': input_file,
'total_variables': len(set(all_var_refs)),
'variable_assignments': len(assignments),
'variable_usage': var_usage,
'numeric_variables': numeric_vars,
'expression_variables': expression_vars,
'dependency_depth': self.calculate_dependency_depth(assignments),
'recommendations': self.generate_recommendations(assignments, var_usage)
}
return report
except Exception as e:
logging.error(f"变量分析失败: {e}")
return None
def calculate_dependency_depth(self, assignments):
"""计算变量依赖深度
Args:
assignments: 变量赋值字典
Returns:
dict: 每个变量的依赖深度
"""
depths = {}
def get_depth(var_name, visited=None):
if visited is None:
visited = set()
if var_name in visited:
return 0 # 循环依赖
if var_name not in assignments:
return 0
if var_name in depths:
return depths[var_name]
visited.add(var_name)
max_depth = 0
for dep in assignments[var_name]['dependencies']:
depth = get_depth(dep, visited.copy())
max_depth = max(max_depth, depth)
depths[var_name] = max_depth + 1
return depths[var_name]
for var_name in assignments:
get_depth(var_name)
return depths
def generate_recommendations(self, assignments, var_usage):
"""生成优化建议
Args:
assignments: 变量赋值
var_usage: 变量使用统计
Returns:
list: 建议列表
"""
recommendations = []
# 检查未使用的变量
for var_name in assignments:
if var_name not in var_usage or var_usage[var_name] <= 1:
recommendations.append(f"变量 @{var_name} 使用次数少,考虑内联或删除")
# 检查简单表达式
import re
for var_name, info in assignments.items():
if len(info['dependencies']) == 0 and re.match(r'^[-+]?\d*\.?\d+$', info['expression']):
recommendations.append(f"变量 @{var_name} 为常量,可直接替换为 {info['expression']}")
# 检查复杂依赖
depths = self.calculate_dependency_depth(assignments)
for var_name, depth in depths.items():
if depth > 3:
recommendations.append(f"变量 @{var_name} 依赖链深度为 {depth},考虑简化")
return recommendations
# 主程序入口
def main():
"""主函数"""
print("=" * 60)
print("数控代码变量处理工具 v4.0")
print("=" * 60)
# 创建流水线
pipeline = NcProcessingPipeline()
# 示例:处理单个文件
input_file = "01001.txt"
if os.path.exists(input_file):
print(f"\n1. 分析文件: {input_file}")
# 生成变量报告
report = pipeline.generate_variable_report(input_file)
if report:
print(f" 发现 {report['total_variables']} 个变量")
print(f" 变量赋值语句: {report['variable_assignments']}")
print(f" 建议: {len(report['recommendations'])} 条")
# 显示前5个最常用的变量
sorted_usage = sorted(report['variable_usage'].items(),
key=lambda x: x[1], reverse=True)[:5]
print(f" 最常用的变量:")
for var, count in sorted_usage:
print(f" @{var}: 使用 {count} 次")
print(f"\n2. 处理文件")
# 设置初始变量值
initial_values = {'1107': 10.0} # 根据实际情况修改
# 处理文件
result = pipeline.process_single_file(
input_file=input_file,
output_file="processed_output.txt",
initial_values=initial_values
)
if result['status'] == 'success':
print(f" 处理成功!")
print(f" 输出文件: {result['output_file']}")
print(f" 处理时间: {result['processing_time']:.2f}秒")
print(f" 压缩率: {result['compression_ratio']:.1f}%")
else:
print(f" 处理失败: {result['message']}")
else:
print(f"\n文件 {input_file} 不存在")
print("\n创建示例文件...")
# 创建示例文件
example_content = """% 示例数控代码
G58;
G90 G00 B-50.00000;
@1017: = 0.6427876096865394*@1107;
@1018: = -0.766044443118978*@1107;
@1144: = 8.21951 + @1017;
@1145: = 94.79563 + @1018;
G00 Z@1145;
G00 X@1144;
G00 Y60.12500;
G00 C0.00000;
G01 Y50.12500 X@1144 Z@1145 C0.00000 F1000.0;"""
with open("example_nc.txt", "w") as f:
f.write(example_content)
print("已创建 example_nc.txt 文件")
print("\n" + "=" * 60)
print("处理完成!")
print("=" * 60)
if __name__ == "__main__":
main()

344

被折叠的 条评论
为什么被折叠?



