从脚本到python:脚本化办公

import os   # Import the os module to interact with the operating system
import sys  # Import the sys module to access system-specific parameters and functions
import re   # Import the re module for regular expression operations
import gzip # Import the gzip module to handle .gz files

# Default search directory and output file path
DEFAULT_SEARCH_DIRECTORY = '/proj'
DEFAULT_OUTPUT_FILE_PATH = '/home/search_and_sort.txt'

# Function to find all relevant files in a given directory and its subdirectories
def find_files(directory):
    # Print a message indicating that the script is finding files in the specified directory
    print("Finding files in " + directory + "...")
    matches = []  # Initialize an empty list to store the paths of matching files
    # Walk through the directory tree starting from the specified directory
    for root, dirs, files in os.walk(directory):
        # Iterate over each file in the current directory
        for file in files:
            # Check if the file name contains 'collapse_feedthru.' or 'summary' and ends with '.rpt.gz'
            if ('collapse_feedthru.' in file or 'summary' in file) and file.endswith('.rpt.gz'):
                # Append the full path of the file to the matches list
                matches.append(os.path.join(root, file))
                # Print a message indicating that a matching file has been found
                print("Found file: " + os.path.join(root, file))
    return matches  # Return the list of matching file paths

# Function to extract collapse summary from a file
def extract_collapse_summary(file_path):
    # Print a message indicating that the script is processing the specified file
    print("Processing file: " + file_path)
    try:
        # Open the gzip compressed file in text read mode
        with gzip.open(file_path, 'rt') as file:
            matched_lines = []  # Initialize an empty list to store matched lines
            # Iterate over each line in the file
            for line in file:
                # Use a regular expression to search for the specific pattern in the line
                match = re.search(r'(w+)scollapses+summarys*#pre:s*(d+)s*#post:s*(d+)s*#deleted:s*(d+)s*collapse%s*:s*(d+.d+)%', line)
                # If a match is found
                if match:
                    # Extract the values
                    tile_name = match.group(1)
                    pre_count = int(match.group(2))
                    post_count = int(match.group(3))
                    deleted_count = int(match.group(4))
                    collapse_ratio = float(match.group(5))
                    # Print the matched line
                    print("Matched line in " + file_path + ": " + line.strip())
                    # Append the tuple (collapse_ratio, tile_name, pre_count, post_count, deleted_count, file_path) to the matched_lines list
                    matched_lines.append((collapse_ratio, tile_name, pre_count, post_count, deleted_count, file_path))
            # If no valid line is found, print a message indicating no matches were found
            if not matched_lines:
                print("No matching lines found in " + file_path)
            return matched_lines
    except Exception as e:
        # If an error occurs while reading the file, print an error message
        print("Error reading " + file_path + ": " + str(e))
        return []

# Main function to perform the search and write results to a file
def main(search_directory, output_file_path):
    # Find all relevant files in the specified directory
    files = find_files(search_directory)
    
    results = []  # Initialize an empty list to store the results

    # Process each file to extract collapse summary information
    for file in files:
        # Extract the collapse summary information from the file
        matched_data = extract_collapse_summary(file)
        # If matched_data is a list of tuples, process each tuple
        if matched_data:
            for collapse_ratio, tile_name, pre_count, post_count, deleted_count, file_path in matched_data:
                # Append a tuple of (collapse_ratio, tile_name, pre_count, post_count, deleted_count, file_path) to the results list
                results.append((collapse_ratio, tile_name, pre_count, post_count, deleted_count, file_path))

    # Sort results based on the collapse ratio (descending order), and put non-matching files last
    results.sort(key=lambda x: (-x[0], x[1]))

    # Determine column widths for alignment
    col_widths = [
        max(len("Collapse_Ratio"), max(len("{:.2f}".format(result[0])) for result in results)),
        max(len("Tile_Name"), max(len(result[1]) for result in results)),
        len("#pre"),
        len("#post"),
        len("#deleted"),
        max(len("File_Path"), max(len(result[5]) for result in results))
    ]

    # Print a header for the sorted results
    print("
Sorted Results:")
    # Print header row with aligned columns using underscores instead of spaces
    print("{:<{}}	{:<{}}	{:<{}}	{:<{}}	{:<{}}	{}".format(
        "Collapse_Ratio", col_widths[0],
        "Tile_Name", col_widths[1],
        "#pre", col_widths[2],
        "#post", col_widths[3],
        "#deleted", col_widths[4],
        "File_Path"
    ))
    # Iterate over each result and print it with aligned columns
    for result in results:
        print("{:<{}}	{:<{}}	{:<{}}	{:<{}}	{:<{}}	{}".format(
            "{:.2f}".format(result[0]), col_widths[0],
            result[1], col_widths[1],
            result[2], col_widths[2],
            result[3], col_widths[3],
            result[4], col_widths[4],
            result[5]
        ))

    # Write sorted results to a txt file
    with open(output_file_path, 'w') as output_file:
        # Write header row with aligned columns using underscores instead of spaces
        output_file.write("{:<{}}	{:<{}}	{:<{}}	{:<{}}	{:<{}}	{}
".format(
            "Collapse_Ratio", col_widths[0],
            "Tile_Name", col_widths[1],
            "#pre", col_widths[2],
            "#post", col_widths[3],
            "#deleted", col_widths[4],
            "File_Path"
        ))
        # Iterate over each result and write it to the output file with aligned columns
        for result in results:
            output_file.write("{:<{}}	{:<{}}	{:<{}}	{:<{}}	{:<{}}	{}
".format(
                "{:.2f}".format(result[0]), col_widths[0],
                result[1], col_widths[1],
                result[2], col_widths[2],
                result[3], col_widths[3],
                result[4], col_widths[4],
                result[5]
            ))

if __name__ == "__main__":
    # Determine the input function based on Python version
    if sys.version_info[0] < 3:
        input_function = raw_input  # Use raw_input for Python 2.x
    else:
        input_function = input  # Use input for Python 3.x

    # Prompt the user to enter the directory to search or press Enter to use the default
    search_directory = input_function("Enter the directory to search (or press Enter for default '" + DEFAULT_SEARCH_DIRECTORY + "'): ").strip()
    if not search_directory:
        search_directory = DEFAULT_SEARCH_DIRECTORY

    # Prompt the user to enter the path for the output file or press Enter to use the default
    output_file_path = input_function("Enter the path for the output file (or press Enter for default '" + DEFAULT_OUTPUT_FILE_PATH + "'): ").strip()
    if not output_file_path:
        output_file_path = DEFAULT_OUTPUT_FILE_PATH

    # Call the main function with the specified search directory and output file path
    main(search_directory, output_file_path)

逐行分析的详细内容:

import os: 导入 os 模块,该模块提供了与操作系统交互的功能,如文件和目录操作。

import sys  # Import the sys module to access system-specific parameters and functions

import sys: 导入 sys 模块,该模块提供了访问系统特定参数和函数的功能,如标准输入输出流、命令行参数等。

import re   # Import the re module for regular expression operations

import re: 导入 re 模块,该模块提供了正则表达式操作的功能,用于模式匹配和文本处理。

import gzip # Import the gzip module to handle .gz files

import gzip: 导入 gzip 模块,该模块提供了处理 .gz 文件的功能,允许读取和写入压缩文件。

# Default search directory and output file path
DEFAULT_SEARCH_DIRECTORY = '/proj/navi44-pdfcfp4-backup/mzhang/preNLD/reuse_wrapper/20230401/main/pd/tiles/run2/rpts/'
DEFAULT_OUTPUT_FILE_PATH = '/home/hanzeliu/result/collapse_search_and_sort.txt'

DEFAULT_SEARCH_DIRECTORY: 定义一个常量 DEFAULT_SEARCH_DIRECTORY,表示默认的搜索目录路径。
DEFAULT_OUTPUT_FILE_PATH: 定义一个常量 DEFAULT_OUTPUT_FILE_PATH,表示默认的输出文件路径。

# Function to find all relevant files in a given directory and its subdirectories
def find_files(directory):
    # Print a message indicating that the script is finding files in the specified directory
    print("Finding files in " + directory + "...")
    matches = []  # Initialize an empty list to store the paths of matching files
    # Walk through the directory tree starting from the specified directory
    for root, dirs, files in os.walk(directory):
        # Iterate over each file in the current directory
        for file in files:
            # Check if the file name contains 'collapse_feedthru.' or 'summary' and ends with '.rpt.gz'
            if ('collapse_feedthru.' in file or 'summary' in file) and file.endswith('.rpt.gz'):
                # Append the full path of the file to the matches list
                matches.append(os.path.join(root, file))
                # Print a message indicating that a matching file has been found
                print("Found file: " + os.path.join(root, file))
    return matches  # Return the list of matching file paths

def find_files(directory):: 定义一个名为 find_files 的函数,接受一个参数 directory,用于指定要搜索的目录。
print("Finding files in " + directory + "..."): 打印一条消息,指示脚本正在指定目录中查找文件。
matches = []: 初始化一个空列表 matches,用于存储匹配文件的路径。
for root, dirs, files in os.walk(directory):: 使用 os.walk 函数遍历指定目录及其子目录,返回三个值:当前目录路径 root、子目录列表 dirs 和文件列表 files
for file in files:: 遍历当前目录中的每个文件。
if ('collapse_feedthru.' in file or 'summary' in file) and file.endswith('.rpt.gz'):: 检查文件名是否包含 'collapse_feedthru.''summary' 并且以 '.rpt.gz' 结尾。
matches.append(os.path.join(root, file)): 将匹配文件的完整路径添加到 matches 列表中。
print("Found file: " + os.path.join(root, file)): 打印找到的文件路径。
return matches: 返回包含所有匹配文件路径的列表。

# Function to extract collapse summary from a file
def extract_collapse_summary(file_path):
    # Print a message indicating that the script is processing the specified file
    print("Processing file: " + file_path)
    try:
        # Open the gzip compressed file in text read mode
        with gzip.open(file_path, 'rt') as file:
            matched_lines = []  # Initialize an empty list to store matched lines
            # Iterate over each line in the file
            for line in file:
                # Use a regular expression to search for the specific pattern in the line
                match = re.search(r'(w+)scollapses+summarys*#pre:s*(d+)s*#post:s*(d+)s*#deleted:s*(d+)s*collapse%s*:s*(d+.d+)%', line)
                # If a match is found
                if match:
                    # Extract the values
                    tile_name = match.group(1)
                    pre_count = int(match.group(2))
                    post_count = int(match.group(3))
                    deleted_count = int(match.group(4))
                    collapse_ratio = float(match.group(5))
                    # Print the matched line
                    print("Matched line in " + file_path + ": " + line.strip())
                    # Append the tuple (collapse_ratio, tile_name, pre_count, post_count, deleted_count, file_path) to the matched_lines list
                    matched_lines.append((collapse_ratio, tile_name, pre_count, post_count, deleted_count, file_path))
            # If no valid line is found, print a message indicating no matches were found
            if not matched_lines:
                print("No matching lines found in " + file_path)
            return matched_lines
    except Exception as e:
        # If an error occurs while reading the file, print an error message
        print("Error reading " + file_path + ": " + str(e))
        return []

def extract_collapse_summary(file_path):: 定义一个名为 extract_collapse_summary 的函数,接受一个参数 file_path,用于指定要处理的文件路径。
print("Processing file: " + file_path): 打印一条消息,指示脚本正在处理指定文件。
try:: 开始一个异常处理块,用于捕获和处理可能发生的错误。
with gzip.open(file_path, 'rt') as file:: 使用 gzip.open 函数打开指定的 .gz 文件,并将其作为文本文件读取。使用 with 语句确保文件在使用后自动关闭。
matched_lines = []: 初始化一个空列表 matched_lines,用于存储匹配的行。
for line in file:: 遍历文件中的每一行。
match = re.search(r'(w+)scollapses+summarys*#pre:s*(d+)s*#post:s*(d+)s*#deleted:s*(d+)s*collapse%s*:s*(d+.d+)%', line): 使用正则表达式在当前行中搜索特定模式,并将匹配结果存储在 match 变量中。
if match:: 如果找到了匹配项,则执行以下代码。
tile_name = match.group(1): 提取匹配的第一个组(即 tile 名称)并赋值给 tile_name
pre_count = int(match.group(2)): 提取匹配的第二个组(即 #pre 计数),转换为整数并赋值给 pre_count
post_count = int(match.group(3)): 提取匹配的第三个组(即 #post 计数),转换为整数并赋值给 post_count
deleted_count = int(match.group(4)): 提取匹配的第四个组(即 #deleted 计数),转换为整数并赋值给 deleted_count
collapse_ratio = float(match.group(5)): 提取匹配的第五个组(即 collapse% 比率),转换为浮点数并赋值给 collapse_ratio
print("Matched line in " + file_path + ": " + line.strip()): 打印匹配的行,去除行末的换行符。
matched_lines.append((collapse_ratio, tile_name, pre_count, post_count, deleted_count, file_path)): 将提取的数据作为一个元组添加到 matched_lines 列表中。
if not matched_lines:: 如果没有找到任何匹配的行,则执行以下代码。
print("No matching lines found in " + file_path): 打印一条消息,指示没有找到匹配的行。
return matched_lines: 返回包含所有匹配行数据的列表。
except Exception as e:: 捕获并处理所有类型的异常。
print("Error reading " + file_path + ": " + str(e)): 打印错误信息。
return []: 返回一个空列表。

# Main function to perform the search and write results to a file
def main(search_directory, output_file_path):
    # Find all relevant files in the specified directory
    files = find_files(search_directory)
    
    results = []  # Initialize an empty list to store the results

    # Process each file to extract collapse summary information
    for file in files:
        # Extract the collapse summary information from the file
        matched_data = extract_collapse_summary(file)
        # If matched_data is a list of tuples, process each tuple
        if matched_data:
            for collapse_ratio, tile_name, pre_count, post_count, deleted_count, file_path in matched_data:
                # Append a tuple of (collapse_ratio, tile_name, pre_count, post_count, deleted_count, file_path) to the results list
                results.append((collapse_ratio, tile_name, pre_count, post_count, deleted_count, file_path))

    # Sort results based on the collapse ratio (descending order), and put non-matching files last
    results.sort(key=lambda x: (-x[0], x[1]))

    # Determine column widths for alignment
    col_widths = [
        max(len("Collapse_Ratio"), max(len("{:.2f}".format(result[0])) for result in results)),
        max(len("Tile_Name"), max(len(result[1]) for result in results)),
        len("#pre"),
        len("#post"),
        len("#deleted"),
        max(len("File_Path"), max(len(result[5]) for result in results))
    ]

    # Print a header for the sorted results
    print("
Sorted Results:")
    # Print header row with aligned columns using underscores instead of spaces
    print("{:<{}}	{:<{}}	{:<{}}	{:<{}}	{:<{}}	{}".format(
        "Collapse_Ratio", col_widths[0],
        "Tile_Name", col_widths[1],
        "#pre", col_widths[2],
        "#post", col_widths[3],
        "#deleted", col_widths[4],
        "File_Path"
    ))
    # Iterate over each result and print it with aligned columns
    for result in results:
        print("{:<{}}	{:<{}}	{:<{}}	{:<{}}	{:<{}}	{}".format(
            "{:.2f}".format(result[0]), col_widths[0],
            result[1], col_widths[1],
            result[2], col_widths[2],
            result[3], col_widths[3],
            result[4], col_widths[4],
            result[5]
        ))

    # Write sorted results to a txt file
    with open(output_file_path, 'w') as output_file:
        # Write header row with aligned columns using underscores instead of spaces
        output_file.write("{:<{}}	{:<{}}	{:<{}}	{:<{}}	{:<{}}	{}
".format(
            "Collapse_Ratio", col_widths[0],
            "Tile_Name", col_widths[1],
            "#pre", col_widths[2],
            "#post", col_widths[3],
            "#deleted", col_widths[4],
            "File_Path"
        ))
        # Iterate over each result and write it to the output file with aligned columns
        for result in results:
            output_file.write("{:<{}}	{:<{}}	{:<{}}	{:<{}}	{:<{}}	{}
".format(
                "{:.2f}".format(result[0]), col_widths[0],
                result[1], col_widths[1],
                result[2], col_widths[2],
                result[3], col_widths[3],
                result[4], col_widths[4],
                result[5]
            ))

def main(search_directory, output_file_path):: 定义一个名为 main 的函数,接受两个参数 search_directoryoutput_file_path,分别用于指定搜索目录和输出文件路径。
files = find_files(search_directory): 调用 find_files 函数获取所有匹配文件的路径,并将结果存储在 files 列表中。
results = []: 初始化一个空列表 results,用于存储所有提取的数据。
for file in files:: 遍历 files 列表中的每个文件路径。
matched_data = extract_collapse_summary(file): 调用 extract_collapse_summary 函数提取当前文件中的数据,并将结果存储在 matched_data 列表中。
if matched_data:: 如果 matched_data 不为空,则执行以下代码。
for collapse_ratio, tile_name, pre_count, post_count, deleted_count, file_path in matched_data:: 遍历 matched_data 列表中的每个元组。
results.append((collapse_ratio, tile_name, pre_count, post_count, deleted_count, file_path)): 将提取的数据作为一个元组添加到 results 列表中。
results.sort(key=lambda x: (-x[0], x[1])): 对 results 列表按 collapse_ratio 降序排序,如果 collapse_ratio 相同,则按 tile_name 排序。
col_widths = [: 初始化一个列表 col_widths,用于存储每列的最大宽度。
max(len("Collapse_Ratio"), max(len("{:.2f}".format(result[0])) for result in results)),: 计算 Collapse_Ratio 列的最大宽度。
max(len("Tile_Name"), max(len(result[1]) for result in results)),: 计算 Tile_Name 列的最大宽度。
len("#pre"),: 计算 #pre 列的固定宽度。
len("#post"),: 计算 #post 列的固定宽度。
len("#deleted"),: 计算 #deleted 列的固定宽度。
max(len("File_Path"), max(len(result[5]) for result in results)): 计算 File_Path 列的最大宽度。
]: 结束 col_widths 列表的定义。
print("
Sorted Results:")
: 打印一条消息,指示接下来是排序后的结果。
print("{:<{}} {:<{}} {:<{}} {:<{}} {:<{}} {}".format(...)): 使用 str.format 方法打印标题行,确保每一列对齐,并将空格替换为下划线。
"{:<{}} {:<{}} {:<{}} {:<{}} {:<{}} {}": 格式化字符串,用于控制每列的宽度和对齐方式。
for result in results:: 遍历 results 列表中的每个元组。
print("{:<{}} {:<{}} {:<{}} {:<{}} {:<{}} {}".format(...)): 使用 str.format 方法打印每一行数据,确保每一列对齐。
with open(output_file_path, 'w') as output_file:: 打开指定的输出文件,准备写入数据。
output_file.write("{:<{}} {:<{}} {:<{}} {:<{}} {:<{}} {}
".format(...))
: 写入标题行到文件,确保每一列对齐,并将空格替换为下划线。
for result in results:: 遍历 results 列表中的每个元组。
output_file.write("{:<{}} {:<{}} {:<{}} {:<{}} {:<{}} {}
".format(...))
: 写入每一行数据到文件,确保每一列对齐。

if __name__ == "__main__":
    # Determine the input function based on Python version
    if sys.version_info[0] < 3:
        input_function = raw_input  # Use raw_input for Python 2.x
    else:
        input_function = input  # Use input for Python 3.x

    # Prompt the user to enter the directory to search or press Enter to use the default
    search_directory = input_function("Enter the directory to search (or press Enter for default '" + DEFAULT_SEARCH_DIRECTORY + "'): ").strip()
    if not search_directory:
        search_directory = DEFAULT_SEARCH_DIRECTORY

    # Prompt the user to enter the path for the output file or press Enter to use the default
    output_file_path = input_function("Enter the path for the output file (or press Enter for default '" + DEFAULT_OUTPUT_FILE_PATH + "'): ").strip()
    if not output_file_path:
        output_file_path = DEFAULT_OUTPUT_FILE_PATH

    # Call the main function with the specified search directory and output file path
    main(search_directory, output_file_path)

if __name__ == "__main__":: 检查当前模块是否作为主程序运行,如果是,则执行以下代码。
if sys.version_info[0] < 3:: 检查当前 Python 版本是否小于 3.0。
input_function = raw_input: 如果是 Python 2.x,则将 input_function 设置为 raw_input
else:: 否则,即 Python 3.x。
input_function = input: 将 input_function 设置为 input
search_directory = input_function(...): 提示用户输入搜索目录路径,如果用户未输入,则使用默认路径。
if not search_directory:: 如果用户未输入搜索目录路径。
search_directory = DEFAULT_SEARCH_DIRECTORY: 使用默认搜索目录路径。
output_file_path = input_function(...): 提示用户输入输出文件路径,如果用户未输入,则使用默认路径。
if not output_file_path:: 如果用户未输入输出文件路径。
output_file_path = DEFAULT_OUTPUT_FILE_PATH: 使用默认输出文件路径。
main(search_directory, output_file_path): 调用 main 函数,传入用户指定的搜索目录和输出文件路径。

总结

通过逐行分析,我们可以理解脚本中使用的各种语法元素和功能模块。以下是关键部分的总结:

导入模块: 使用 import 语句导入所需的模块,如 ossysregzip
常量定义: 使用大写字母定义常量 DEFAULT_SEARCH_DIRECTORYDEFAULT_OUTPUT_FILE_PATH
函数定义: 使用 def 关键字定义函数 find_filesextract_collapse_summarymain
列表: 使用方括号 [] 创建和操作列表,例如 matchesresults
字符串: 使用引号 ''"" 创建字符串,例如 "Finding files in ""Processing file: ".
格式化字符串: 使用 str.format 方法格式化输出字符串,确保对齐和替换空格为下划线。
异常处理: 使用 tryexcept 块捕获和处理异常。
条件判断: 使用 if 语句进行条件判断,例如检查文件名是否匹配特定模式。
循环: 使用 for 循环遍历文件和行。
文件操作: 使用 openwith 语句进行文件读取和写入操作。
好的,我会逐一解释你提到的各个部分,并明确指出哪些是关键字、哪些是变量。

常量定义

DEFAULT_SEARCH_DIRECTORY = '/proj/navi44-pdfcfp4-backup/mzhang/preNLD/reuse_wrapper/20230401/main/pd/tiles/run2/rpts/'

DEFAULT_SEARCH_DIRECTORY: 这是一个常量,用于存储默认的搜索目录路径。
'/proj/navi44-pdfcfp4-backup/mzhang/preNLD/reuse_wrapper/20230401/main/pd/tiles/run2/rpts/': 这是一个字符串字面量,表示具体的目录路径。

字符串字面量的区别

单引号 (') 和双引号 ("): 在 Python 中,单引号和双引号都可以用来定义字符串。例如:

string1 = 'Hello'
string2 = "World"

它们在大多数情况下是可以互换的,但当字符串本身包含引号时,可以使用另一种引号来避免转义字符。例如:

string3 = 'He said, "Hello!"'
string4 = "It's a sunny day."

三重引号 ('''"""): 三重引号用于多行字符串或文档字符串(docstring)。例如:

multi_line_string = '''This is a multi-line string.
It can span multiple lines.'''
docstring_example = """This is a docstring.
It provides documentation for functions or modules."""

os.walk 函数

os.walkos 模块中的一个函数,用于遍历指定目录及其子目录中的文件和目录。其基本语法如下:

for root, dirs, files in os.walk(top, topdown=True, onerror=None, followlinks=False):
    # 处理每个目录和文件

top: 要遍历的顶级目录。
root: 当前遍历的目录路径。
dirs: 当前目录下的子目录列表。
files: 当前目录下的文件列表。

file.endswith 方法

endswith 是字符串对象的一个方法,用于检查字符串是否以指定的后缀结尾。其基本语法如下:

bool_value = string.endswith(suffix)

suffix: 要检查的后缀字符串。
bool_value: 返回布尔值,如果字符串以指定后缀结尾,则返回 True,否则返回 False

try 语句

try 语句用于异常处理,捕获代码块中可能发生的异常并进行处理。其基本语法如下:

try:
    # 可能引发异常的代码
except ExceptionType as e:
    # 异常处理代码

try: 关键字,开始一个异常处理块。
except: 关键字,捕获特定类型的异常。
ExceptionType: 异常类型,如 ValueError, IOError 等。
e: 变量,用于存储捕获的异常实例。

with 语句

with 语句用于上下文管理,确保资源(如文件)在使用后正确释放。其基本语法如下:

with expression as target:
    # 使用目标对象的代码

with: 关键字,开始一个上下文管理器。
expression: 表达式,通常返回一个实现了上下文管理协议的对象(如文件对象)。
as: 关键字,将表达式的返回值赋给目标变量。
target: 目标变量,用于存储上下文管理器返回的对象。

'rt' 模式

'rt' 是文件打开模式,用于指定文件的读取方式。其中:

r: 以只读模式打开文件。
t: 以文本模式打开文件。

match.group 方法

group 是正则表达式匹配对象的方法,用于提取匹配的子组。其基本语法如下:

value = match.group(group_number)

match: 正则表达式匹配对象。
group_number: 子组编号,从 1 开始。
value: 提取的子组内容。

正则表达式中的子组

在正则表达式中,子组(也称为捕获组)是由圆括号 () 包围的部分。每个子组会在匹配成功时被捕获,并且可以通过 match.group(n) 方法来提取这些子组的内容。以下是详细的解释和示例:

基本概念

子组 (Capturing Group): 由一对圆括号 () 包围的部分。
索引: 子组的索引从 1 开始,按它们在正则表达式中出现的顺序编号。
命名子组: 可以使用 (?P<name>...) 的形式为子组命名,便于通过名称访问。

示例

假设我们有以下正则表达式和字符串:

import re

pattern = r'(w+)scollapses+summarys*#pre:s*(d+)s*#post:s*(d+)s*#deleted:s*(d+)s*collapse%s*:s*(d+.d+)%'
line = "tile1 collapse summary #pre: 100 #post: 80 #deleted: 20 collapse%: 20.0%"
match = re.search(pattern, line)
解析正则表达式
(w+)scollapses+summarys*#pre:s*(d+)s*#post:s*(d+)s*#deleted:s*(d+)s*collapse%s*:s*(d+.d+)%

(w+): 第一个子组,匹配一个或多个字母、数字或下划线(即 tile_name)。
scollapses+summarys*: 匹配字符串 "collapse summary",前后可以有空格。
#pre:s*(d+)s*: 匹配字符串 "#pre:" 后面跟着一个或多个数字(即 pre_count)。
#post:s*(d+)s*: 匹配字符串 "#post:" 后面跟着一个或多个数字(即 post_count)。
#deleted:s*(d+)s*: 匹配字符串 "#deleted:" 后面跟着一个或多个数字(即 deleted_count)。
collapse%s*:s*(d+.d+): 匹配字符串 "collapse%:" 后面跟着一个小数(即 collapse_ratio)。

提取子组内容

如果匹配成功,match 对象将包含所有捕获的子组。你可以使用 match.group(n) 方法来提取第 n 个子组的内容。

if match:
    tile_name = match.group(1)       # 提取第一个子组的内容
    pre_count = int(match.group(2))  # 提取第二个子组的内容并转换为整数
    post_count = int(match.group(3)) # 提取第三个子组的内容并转换为整数
    deleted_count = int(match.group(4)) # 提取第四个子组的内容并转换为整数
    collapse_ratio = float(match.group(5)) # 提取第五个子组的内容并转换为浮点数

    print(f"Tile Name: {
              tile_name}")
    print(f"Pre Count: {
              pre_count}")
    print(f"Post Count: {
              post_count}")
    print(f"Deleted Count: {
              deleted_count}")
    print(f"Collapse Ratio: {
              collapse_ratio}")
输出结果
Tile Name: tile1
Pre Count: 100
Post Count: 80
Deleted Count: 20
Collapse Ratio: 20.0

具体步骤

定义正则表达式模式:

pattern = r'(w+)scollapses+summarys*#pre:s*(d+)s*#post:s*(d+)s*#deleted:s*(d+)s*collapse%s*:s*(d+.d+)%'

查找匹配项:

match = re.search(pattern, line)

提取子组内容:

if match:
    tile_name = match.group(1)
    pre_count = int(match.group(2))
    post_count = int(match.group(3))
    deleted_count = int(match.group(4))
    collapse_ratio = float(match.group(5))

命名子组

除了使用数字索引来访问子组外,还可以使用命名子组来提高代码的可读性。命名子组的语法是 (?P<name>...),其中 name 是你给子组起的名字。

示例
import re

pattern = r'(?P<tile_name>w+)scollapses+summarys*#pre:s*(?P<pre_count>d+)s*#post:s*(?P<post_count>d+)s*#deleted:s*(?P<deleted_count>d+)s*collapse%s*:s*(?P<collapse_ratio>d+.d+)%'
line = "tile1 collapse summary #pre: 100 #post: 80 #deleted: 20 collapse%: 20.0%"
match = re.search(pattern, line)

if match:
    tile_name = match.group('tile_name')
    pre_count = int(match.group('pre_count'))
    post_count = int(match.group('post_count'))
    deleted_count = int(match.group('deleted_count'))
    collapse_ratio = float(match.group('collapse_ratio'))

    print(f"Tile Name: {
              tile_name}")
    print(f"Pre Count: {
              pre_count}")
    print(f"Post Count: {
              post_count}")
    print(f"Deleted Count: {
              deleted_count}")
    print(f"Collapse Ratio: {
              collapse_ratio}")
输出结果
Tile Name: tile1
Pre Count: 100
Post Count: 80
Deleted Count: 20
Collapse Ratio: 20.0

总结

子组: 由圆括号 () 包围的部分。
索引: 子组的索引从 1 开始,按它们在正则表达式中出现的顺序编号。
命名子组: 使用 (?P<name>...) 形式命名子组,便于通过名称访问。
match.group(n): 提取第 n 个子组的内容。
match.group(name): 提取名为 name 的子组的内容。

理解 group 方法如何划分子组的关键在于正则表达式模式中的圆括号 ()子组(捕获组)是由正则表达式中的圆括号定义的,而不是根据换行或空格来划分的。下面我将详细解释这一点,并通过示例来说明。

正则表达式中的子组

在正则表达式中,子组是通过圆括号 () 来定义的。每个子组会捕获匹配到的内容,并可以通过 match.group(n) 方法来提取这些内容。子组的划分完全取决于你在正则表达式中如何使用圆括号,而不是由换行符
或空格 来决定。

示例

假设我们有以下字符串和正则表达式:

import re

line = "tile1 collapse summary #pre: 100 #post: 80 #deleted: 20 collapse%: 20.0%"
pattern = r'(w+)scollapses+summarys*#pre:s*(d+)s*#post:s*(d+)s*#deleted:s*(d+)s*collapse%s*:s*(d+.d+)%'
match = re.search(pattern, line)
解析正则表达式
(w+)scollapses+summarys*#pre:s*(d+)s*#post:s*(d+)s*#deleted:s*(d+)s*collapse%s*:s*(d+.d+)%

(w+): 第一个子组,匹配一个或多个字母、数字或下划线(即 tile_name)。
scollapses+summarys*: 匹配字符串 "collapse summary",前后可以有空格。
#pre:s*(d+)s*: 匹配字符串 "#pre:" 后面跟着一个或多个数字(即 pre_count)。
#post:s*(d+)s*: 匹配字符串 "#post:" 后面跟着一个或多个数字(即 post_count)。
#deleted:s*(d+)s*: 匹配字符串 "#deleted:" 后面跟着一个或多个数字(即 deleted_count)。
collapse%s*:s*(d+.d+): 匹配字符串 "collapse%:" 后面跟着一个小数(即 collapse_ratio)。

子组划分

在这个例子中,子组的划分完全由正则表达式中的圆括号确定,而不是由换行符或空格决定。具体来说:

第一个子组 ((w+)):

捕获 tile1

第二个子组 ((d+)):

捕获 100

第三个子组 ((d+)):

捕获 80

第四个子组 ((d+)):

捕获 20

第五个子组 ((d+.d+)):

捕获 20.0

提取子组内容

如果匹配成功,match 对象将包含所有捕获的子组。你可以使用 match.group(n) 方法来提取第 n 个子组的内容。

if match:
    tile_name = match.group(1)       # 提取第一个子组的内容
    pre_count = int(match.group(2))  # 提取第二个子组的内容并转换为整数
    post_count = int(match.group(3)) # 提取第三个子组的内容并转换为整数
    deleted_count = int(match.group(4)) # 提取第四个子组的内容并转换为整数
    collapse_ratio = float(match.group(5)) # 提取第五个子组的内容并转换为浮点数

    print(f"Tile Name: {
              tile_name}")
    print(f"Pre Count: {
              pre_count}")
    print(f"Post Count: {
              post_count}")
    print(f"Deleted Count: {
              deleted_count}")
    print(f"Collapse Ratio: {
              collapse_ratio}")
输出结果
Tile Name: tile1
Pre Count: 100
Post Count: 80
Deleted Count: 20
Collapse Ratio: 20.0

具体步骤

定义正则表达式模式:

pattern = r'(w+)scollapses+summarys*#pre:s*(d+)s*#post:s*(d+)s*#deleted:s*(d+)s*collapse%s*:s*(d+.d+)%'

查找匹配项:

match = re.search(pattern, line)

提取子组内容:

if match:
    tile_name = match.group(1)
    pre_count = int(match.group(2))
    post_count = int(match.group(3))
    deleted_count = int(match.group(4))
    collapse_ratio = float(match.group(5))

更多示例

为了进一步说明,再来看一个更简单的例子:

示例 1: 空格分隔的单词
import re

line = "Alice 30 New York"
pattern = r'(w+)s+(d+)s+(.*)'
match = re.match(pattern, line)

if match:
    name = match.group(1)       # 提取第一个子组的内容 (名字)
    age = int(match.group(2))     # 提取第二个子组的内容 (年龄)
    city = match.group(3)       # 提取第三个子组的内容 (城市)

    print(f"Name: {
              name}")
    print(f"Age: {
              age}")
    print(f"City: {
              city}")
解析正则表达式
(w+)s+(d+)s+(.*)

(w+): 第一个子组,匹配一个或多个字母、数字或下划线(即 name)。
s+: 匹配一个或多个空格。
(d+): 第二个子组,匹配一个或多个数字(即 age)。
s+: 匹配一个或多个空格。
(.*?): 第三个子组,匹配任意字符(非贪婪模式),直到字符串结束(即 city)。

输出结果
Name: Alice
Age: 30
City: New York
示例 2: 命名子组

使用命名子组可以使代码更具可读性。

import re

line = "Bob 25 Los Angeles"
pattern = r'(?P<name>w+)s+(?P<age>d+)s+(?P<city>.*)'
match = re.match(pattern, line)

if match:
    name = match.group('name')       # 提取名为 'name' 的子组的内容
    age = int(match.group('age'))     # 提取名为 'age' 的子组的内容
    city = match.group('city')       # 提取名为 'city' 的子组的内容

    print(f"Name: {
              name}")
    print(f"Age: {
              age}")
    print(f"City: {
              city}")
解析正则表达式
(?P<name>w+)s+(?P<age>d+)s+(?P<city>.*)

(?P<name>w+): 命名子组 name,匹配一个或多个字母、数字或下划线。
s+: 匹配一个或多个空格。
(?P<age>d+): 命名子组 age,匹配一个或多个数字。
s+: 匹配一个或多个空格。
(?P<city>.*): 命名子组 city,匹配任意字符(非贪婪模式),直到字符串结束。

输出结果
Name: Bob
Age: 25
City: Los Angeles

总结

子组: 由正则表达式中的圆括号 () 定义,而不是由换行符
或空格 划分。
索引: 子组的索引从 1 开始,按它们在正则表达式中出现的顺序编号。
命名子组: 使用 (?P<name>...) 形式命名子组,便于通过名称访问。
match.group(n): 提取第 n 个子组的内容。
match.group(name): 提取名为 name 的子组的内容。

line.strip 方法

strip 是字符串对象的方法,用于去除字符串两端的空白字符(包括空格、制表符 和换行符
)。其基本语法如下:

cleaned_string = line.strip()

line: 原始字符串。
cleaned_string: 去除两端空白字符后的字符串。

int(match.group(4)) 中的 int

int 是内置函数,用于将字符串或其他数值转换为整数。其基本语法如下:

integer_value = int(value)

value: 要转换的值,通常是字符串。
integer_value: 转换后的整数值。

except Exception as e

except 语句用于捕获特定类型的异常,并将其赋值给一个变量以便进一步处理。其基本语法如下:

try:
    # 可能引发异常的代码
except ExceptionType as e:
    # 异常处理代码

except: 关键字,捕获特定类型的异常。
ExceptionType: 异常类型,如 ValueError, IOError 等。
as: 关键字,将捕获的异常实例赋给变量。
e: 变量,用于存储捕获的异常实例。

Python 中的 main 函数与 C 语言的不同

Python:

main 函数不是强制性的入口点。
通常使用 if __name__ == "__main__": 来判断模块是否作为主程序运行。
示例:

def main():
    print("Hello, World!")

if __name__ == "__main__":
    main()

C 语言:

main 函数是程序的入口点,必须存在。
编译器从 main 函数开始执行程序。
示例:

#include <stdio.h>

void main() {
                
    printf("Hello, World!
");
}

extract_collapse_summary 函数

extract_collapse_summary 是自定义函数,用于从指定文件中提取符合特定模式的行,并解析出所需的信息。其定义如下:

def extract_collapse_summary(file_path):
    # 函数体

def: 关键字,定义函数。
extract_collapse_summary: 函数名。
file_path: 函数参数,表示文件路径。

append 方法

append 是列表对象的方法,用于在列表末尾添加一个元素。其基本语法如下:

list_name.append(element)

list_name: 列表对象。
element: 要添加的元素。

格式化字符串

"{:<{}}	{:<{}}	{:<{}}	{:<{}}	{:<{}}	{}"

{}: 占位符,用于插入变量值。
:<{}: 左对齐,并根据指定宽度调整。
: 制表符,用于分隔列。
{}: 具体变量值会被插入到这些占位符位置。

output_file.write 中的变量和语法

output_file.write("{:<{}}	{:<{}}	{:<{}}	{:<{}}	{:<{}}	{}
".format(
    "{:.2f}".format(result[0]), col_widths[0],
    result[1], col_widths[1],
    result[2], col_widths[2],
    result[3], col_widths[3],
    result[4], col_widths[4],
    result[5]
))

output_file: 文件对象,表示输出文件。
write: 文件对象的方法,用于写入字符串。
"{:<{}} {:<{}} {:<{}} {:<{}} {:<{}} {}
"
: 格式化字符串。
.format(...): 方法调用,用于格式化字符串。
"{:.2f}".format(result[0]): 格式化浮点数,保留两位小数。
col_widths[0]: 列宽度,变量。
result[1]: 匹配结果中的第二个元素,变量。
result[2]: 匹配结果中的第三个元素,变量。
result[3]: 匹配结果中的第四个元素,变量。
result[4]: 匹配结果中的第五个元素,变量。
result[5]: 匹配结果中的第六个元素,变量。

if __name__ == "__main__": 中的关键字

if __name__ == "__main__":

if: 关键字,条件判断。
__name__: 特殊变量,表示当前模块的名称。
==: 比较运算符,等于。
__main__: 字符串常量,表示模块作为主程序运行。
:: 冒号,表示代码块的开始。

if not search_directory: 语法

if not search_directory:

if: 关键字,条件判断。
not: 关键字,逻辑非运算符。
search_directory: 变量,表示用户输入的搜索目录路径。

output_file_path = input_function(...) 语法

output_file_path = input_function(...)

output_file_path: 变量,用于存储用户输入的输出文件路径。
=: 赋值运算符。
input_function: 函数名,表示输入函数。
(...): 函数调用,传递参数。

关键字总结

关键字:

import
def
return
print
for
in
if
else
try
except
as
with
open
format
not
while
pass
break
continue
lambda
class
self
from
and
or
is
is not
in
not in
global
nonlocal
del
raise
assert
finally
yield
async
await
async def

变量总结

变量:

os
sys
re
gzip
DEFAULT_SEARCH_DIRECTORY
DEFAULT_OUTPUT_FILE_PATH
directory
matches
root
dirs
files
file
matched_lines
line
match
tile_name
pre_count
post_count
deleted_count
collapse_ratio
results
file_path
search_directory
output_file_path
input_function
file
result
col_widths
output_file
e

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
咪惹Nyaru的头像 - 宋马
评论 抢沙发

请登录后发表评论

    暂无评论内容