You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化硬编码Python脚本,实现多文本文件特定行灵活提取?

LAS文本报告信息提取脚本优化

问题背景

作为Python新手,我借助ChatGPT及本站问答编写了一段脚本,用于处理指定目录下的多个LAS工具生成的.txt报告文件,提取LAS文件名、PROJCS投影信息、点密度等内容。但当前脚本硬编码程度高,依赖固定字符索引切片提取内容,一旦报告格式稍有变化就会失效,希望优化成自动搜索定位目标内容的版本,提升通用性。

原始代码

import os

def extract_lines(input_file, output_file):
    
    with open(input_file, 'r') as file: # Reads in las filename
        linea = [line for line in file if line.startswith('lasinfo')]
        linea = str(linea)
        linea = linea[31:-5]
        if len(linea) == 0:
            linea ='No filename defined!'
        
    with open(input_file, 'r') as file: # Reads in las datum
        lineb = [line for line in file if line.startswith('    PROJCS')]
        lineb = str(lineb)
        lineb = lineb[14:41]
        if len(lineb) == 0:
            lineb ='No DATUM defined!'

    with open(input_file, 'r') as file: # Reads in las point density details
        linec = [line for line in file if line.startswith('point density')]
        linec = str(linec)
        linec = linec[2:-4]
        lined = linec[27:31] # strips out density (points/m) value from statement
        if len(linec) == 0:
            linec ='No point density listed'
        
        lineout = linea + "," + lineb + "," + linec + "," + lined + '\n'

    with open(output_file, 'a') as output:
          output.write(lineout)
          
def process_txt_files(directory_path, output_file): # Scans directory for .txt files to process
    with open(output_file, 'w'):
        pass

    for filename in os.listdir(directory_path):
        if filename.endswith(".txt"):
            file_path = os.path.join(directory_path, filename)
            extract_lines(file_path, output_file)


directory_path = 'C:/Users/rinicholls/Richard/Gnarabup_LiDAR/LiDAR/Gnarabup_South_AVWS/reports'
output_file = 'density.txt'

process_txt_files(directory_path, output_file)

待处理的.txt报告示例

lasinfo (231025) report for 'Gnarabup_South_sph_e310n6230_1AVWS.las'
reporting all LAS header entries:
  file signature:             'LASF'
  file source ID:             0
  global_encoding:            1
  project ID GUID data 1-4:   00000000-0000-0000-0000-000000000000
  version major.minor:        1.4
  system identifier:          'LAStools (c) by rapidlasso GmbH'
  generating software:        'lasheight (210418) commercial'
  file creation day/year:     278/2023
  header size:                375
  offset to point data:       375
  number var. length records: 0
  point data format:          6
  point data record length:   30
  number of point records:    0
  number of points by return: 0 0 0 0 0
  scale factor x y z:         0.01 0.01 0.01
  offset x y z:               0 0 0
  min x y z:                  311439.81 6230000.08 -38.91
  max x y z:                  311999.99 6231999.80 -33.17
  start of waveform data packet record: 0
  start of first extended variable length record: 0
  number of extended_variable length records: 0
  extended number of point records: 7586
  extended number of points by return: 7586 0 0 0 0 0 0 0 0 0 0 0 0 0 0
reporting minimum and maximum for all LAS point record entries ...
  X            31143981   31199999
  Y           623000008  623199980
  Z               -3891      -3317
  intensity           0          0
  return_number       1          1
  number_of_returns   1          1
  edge_of_flight_line 0          1
  scan_direction_flag 0          1
  classification     13         13
  scan_angle_rank   -11         18
  user_data           1          1
  point_source_ID   174        177
  gps_time 363998052.416096 363998902.558917
  extended_return_number          1      1
  extended_number_of_returns      1      1
  extended_classification        13     13
  extended_scan_angle         -1820   2924
  extended_scanner_channel        0      0
number of first returns:        7586
number of intermediate returns: 0
number of last returns:         7586
number of single returns:       7586
covered area in square units/kilounits: 30136/0.03
point density: all returns 0.25 last only 0.25 (per square units)
      spacing: all returns 1.99 last only 1.99 (in units)
overview over extended number of returns of given pulse: 7586 0 0 0 0 0 0 0 0 0 0 0 0 0 0
histogram of classification of points:
            7586  wire guard (13)

优化后的代码

import os
import re

def extract_las_info(file_lines):
    # 提取LAS文件名
    las_filename = "No filename defined!"
    lasinfo_pattern = re.compile(r"lasinfo \(.*\) report for '([^']+)'")
    for line in file_lines:
        match = lasinfo_pattern.match(line.strip())
        if match:
            las_filename = match.group(1)
            break
    
    # 提取PROJCS信息
    projcs_info = "No DATUM defined!"
    projcs_pattern = re.compile(r"    PROJCS:?\s*(.*)")
    for line in file_lines:
        match = projcs_pattern.match(line.strip())
        if match:
            projcs_info = match.group(1).strip()
            break
    
    # 提取点密度信息
    density_info = "No point density listed"
    density_value = ""
    density_pattern = re.compile(r"point density: (.*)")
    value_pattern = re.compile(r"all returns (\d+\.\d+)")
    for line in file_lines:
        match = density_pattern.match(line.strip())
        if match:
            density_info = match.group(1).strip()
            value_match = value_pattern.search(density_info)
            if value_match:
                density_value = value_match.group(1)
            break
    
    return las_filename, projcs_info, density_info, density_value

def extract_lines(input_file, output_file):
    # 一次性读取所有行,减少IO操作
    with open(input_file, 'r') as file:
        file_lines = file.readlines()
    
    las_filename, projcs_info, density_info, density_value = extract_las_info(file_lines)
    
    # 处理密度值为空的情况
    if not density_value and density_info != "No point density listed":
        density_value = "N/A"
    
    lineout = f"{las_filename},{projcs_info},{density_info},{density_value}\n"
    
    with open(output_file, 'a') as output:
        output.write(lineout)

def process_txt_files(directory_path, output_file):
    # 清空输出文件
    with open(output_file, 'w'):
        pass
    
    # 遍历目录下的txt文件
    for filename in os.listdir(directory_path):
        if filename.lower().endswith(".txt"):
            file_path = os.path.join(directory_path, filename)
            extract_lines(file_path, output_file)

# 配置路径
directory_path = 'C:/Users/rinicholls/Richard/Gnarabup_LiDAR/LiDAR/Gnarabup_South_AVWS/reports'
output_file = 'density.txt'

process_txt_files(directory_path, output_file)

优化说明

  • 减少文件IO操作:一次性读取文件所有行,避免重复打开同一文件多次,提升效率
  • 正则表达式提取:不再依赖固定字符索引切片,通过正则匹配目标内容,即使报告格式有小幅度变化(比如空格数量不同)也能正常提取
  • 增强容错性:对缺失信息的场景(如无PROJCS、点密度值无法提取)做了更完善的处理,避免空值或错误内容
  • 代码结构更清晰:将信息提取逻辑封装成单独函数,便于维护和扩展后续需要提取的其他字段

内容的提问来源于stack exchange,提问作者Rich

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 20:35:02