用Python扩展徕卡P40扫描目标程序:从Excel匹配坐标写入TXT
解决方案技术方向与实现代码
核心思路
用pandas库实现类VLOOKUP的坐标匹配功能,把现有代码生成的格式化目标名和CSV/XLSX中的坐标数据关联,最终输出带坐标的TXT文件。同时优化原代码中目标名格式化的逻辑,用正则表达式替代冗余的条件判断,提升代码健壮性。
步骤拆解与实现
1. 安装依赖库
需要pandas处理表格数据,读取XLSX文件还需openpyxl:
pip install pandas openpyxl
2. 优化目标名格式化逻辑
针对控制点格式LL.LLNN.L(n/x),用正则匹配替代多分支判断,更简洁准确:
import re def format_target_name(raw_name): # 截取文件名前半部分(去掉末尾9位) target = raw_name[:-9] # 正则匹配无分隔符的控制点名称,补全标准分隔符 pattern = r'^([A-Za-z]{2})([A-Za-z]{2})(\d{2})([A-Za-z])([nx]?)$' match = re.match(pattern, target) if match: parts = match.groups() # 拼接成标准格式:LL.LLNN.L(n/x) formatted = f"{parts[0]}.{parts[1]}{parts[2]}.{parts[3]}{parts[4]}" return formatted return target # 匹配失败则返回原处理后的名称
3. 读取坐标文件并匹配
用pandas加载CSV/XLSX,以目标名为键做左连接(保留所有提取的目标名,匹配不到坐标则显示空值):
import pandas as pd def load_coords(coords_path): # 根据文件后缀选择读取方式 if coords_path.endswith('.xlsx'): df = pd.read_excel(coords_path, dtype={'控制点名称': str}) # 强制名称为字符串,避免数字转换导致匹配失败 elif coords_path.endswith('.csv'): df = pd.read_csv(coords_path, dtype={'控制点名称': str}) else: raise ValueError("仅支持CSV/XLSX格式的坐标文件") # 假设坐标文件列名为:控制点名称, X, Y, Z,需根据实际修改 return df[['控制点名称', 'X', 'Y', 'Z']] def match_targets_with_coords(targets_list, coords_df): # 将目标名列表转为DataFrame targets_df = pd.DataFrame({'控制点名称': targets_list}) # 左连接实现类VLOOKUP精确匹配 merged_df = pd.merge(targets_df, coords_df, on='控制点名称', how='left') return merged_df
4. 写入带坐标的TXT文件
将匹配结果按目标名,X,Y,Z格式写入文件,空坐标用NA标记:
def write_targets_with_coords(merged_df, output_path): with open(output_path, 'w', encoding='utf-8') as f: # 写入表头(可选,若不需要可删除) f.write("控制点名称,X,Y,Z\n") for _, row in merged_df.iterrows(): target = row['控制点名称'] x = row['X'] if pd.notna(row['X']) else 'NA' y = row['Y'] if pd.notna(row['Y']) else 'NA' z = row['Z'] if pd.notna(row['Z']) else 'NA' f.write(f"{target},{x},{y},{z}\n")
完整整合代码
import os import re import pandas as pd def format_target_name(raw_name): target = raw_name[:-9] pattern = r'^([A-Za-z]{2})([A-Za-z]{2})(\d{2})([A-Za-z])([nx]?)$' match = re.match(pattern, target) if match: parts = match.groups() formatted = f"{parts[0]}.{parts[1]}{parts[2]}.{parts[3]}{parts[4]}" return formatted return target def load_coords(coords_path): if coords_path.endswith('.xlsx'): df = pd.read_excel(coords_path, dtype={'控制点名称': str}) elif coords_path.endswith('.csv'): df = pd.read_csv(coords_path, dtype={'控制点名称': str}) else: raise ValueError("仅支持CSV/XLSX格式的坐标文件") return df[['控制点名称', 'X', 'Y', 'Z']] def match_targets_with_coords(targets_list, coords_df): targets_df = pd.DataFrame({'控制点名称': targets_list}) merged_df = pd.merge(targets_df, coords_df, on='控制点名称', how='left') return merged_df def write_targets_with_coords(merged_df, output_path): with open(output_path, 'w', encoding='utf-8') as f: f.write("控制点名称,X,Y,Z\n") for _, row in merged_df.iterrows(): target = row['控制点名称'] x = row['X'] if pd.notna(row['X']) else 'NA' y = row['Y'] if pd.notna(row['Y']) else 'NA' z = row['Z'] if pd.notna(row['Z']) else 'NA' f.write(f"{target},{x},{y},{z}\n") if __name__ == "__main__": # 输入路径 p = input("请输入原始扫描数据文件夹路径:") controlpath = input("请输入输出文件保存路径:") coords_path = input("请输入坐标文件(CSV/XLSX)路径:") # 提取并去重目标文件名 targets = [] for root, directories, contents in os.walk(p, topdown=False): for name in contents: # 过滤不需要的文件 if "Scan" in name or len(name) < 13 or "Project" in name: continue if name not in targets: targets.append(name) # 格式化目标名 formatted_targets = [format_target_name(target) for target in targets] # 加载坐标并匹配 coords_df = load_coords(coords_path) merged_df = match_targets_with_coords(formatted_targets, coords_df) # 写入带坐标的TXT output_file = os.path.join(controlpath, "control_with_coords.txt") write_targets_with_coords(merged_df, output_file) print(f"带坐标的控制点文件已生成:{output_file}")
关键注意事项
- 确保坐标文件中的控制点名称列名与代码中的
控制点名称一致,若实际列名不同,需修改代码中对应的列名。 - 正则表达式可根据实际控制点格式调整,若存在特殊格式,可扩展正则规则。
- 匹配时强制名称为字符串类型,避免数字型名称被自动转换导致匹配失败。
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

