首页 > 其他分享 >py脚本一:业务中excel报表处理

py脚本一:业务中excel报表处理

时间:2024-10-10 11:32:52浏览次数:8  
标签:index 报表 df py excel cell column print columns

excel报表处理

根据业务需求,每月都要对报表处理一次,手动太麻烦,还容易出错,用py脚本,实现对应处理,能更快;个人需求可能并不符合所有要求

  • 涉及python模块
    pandas、numpy、re
  • 代码:
import pandas as pd
import numpy as np
import re
import os

def list_columns(df):
    print("列名标号:")
    for i, col in enumerate(df.columns):
        print(f"{i}: {col}")

def remove_columns_from_excel(df):#1列表删除
    list_columns(df)
    selected_columns = input("请输入要保留的列的标号(以空格分隔): ").split()
    selected_columns = [int(col) for col in selected_columns]
    return df.iloc[:, selected_columns]

def clean_urls_in_column(df):#2url匹配
    list_columns(df)
    column_index = int(input("请输入URL所在列的标号: "))

    # 正则表达式匹配基本的URL结构
    url_pattern = re.compile(r'^(https?://)?([\w\-\.]+)(\.\w+)(/[\w\-\.]*)*')

    def clean_url(cell):
        if pd.isna(cell) or cell in ['undefined', 'NaN', 'NaN//undefined', '待确认']:
            return ""

        # 确保cell是字符串
        cell = str(cell).strip()

        # 去除两侧的引号
        if cell.startswith('"') and cell.endswith('"'):
            cell = cell[1:-1]

        # 修正分隔符(将逗号、中文逗号等替换为点)
        cell = re.sub(r'[,,]', '.', cell)

        # 使用正则表达式匹配并修复URL
        match = url_pattern.match(cell)
        if match:
            protocol = match.group(1) or "http://"
            domain = match.group(2) + match.group(3)
            path = match.group(4) or ""
            return f"{protocol}{domain}{path}"
        else:
            return ""

    df.iloc[:, column_index] = df.iloc[:, column_index].apply(clean_url)
    return df

def filter_and_delete_rows(df):#3
    list_columns(df)
    column_index = int(input("请输入要操作的列的标号: "))

    # 获取唯一值列表,包括空值
    unique_values = df.iloc[:, column_index].unique()
    value_to_index = {str(i): v for i, v in enumerate(unique_values) if pd.notna(v)}

    # 添加空值选项
    if df.iloc[:, column_index].isnull().any():
        value_to_index[str(len(value_to_index))] = None

    # 列出所有唯一值并标号
    print("可用的筛选条件:")
    for i, value in value_to_index.items():
        display_value = value if value is not None else '空值'
        print(f"{i}: {display_value}")

    # 接收用户输入的标号
    condition_indexes = input("请输入要删除的条件标号(可以输入多个标号,用空格分隔): ").split()

    # 将输入的标号转换为对应的值
    conditions_to_delete = [value_to_index.get(idx) for idx in condition_indexes if idx in value_to_index]

    # 筛选并删除符合条件的行,包括空值
    df = df[~df.iloc[:, column_index].isin(conditions_to_delete) & ~df.iloc[:, column_index].isnull()]

    return df

def search_and_delete(df):#4
    list_columns(df)
    print("选择删除方式:")
    print("1: 删除整行")
    print("2: 仅删除单元格内容")
    delete_option = int(input("请输入选项: "))

    search_terms = input("请输入要检索的内容(多个内容请用空格分隔): ").split()

    if delete_option == 1:
        df = df[~df.apply(lambda row: any(term in str(cell) for term in search_terms for cell in row), axis=1)]
    elif delete_option == 2:
        def clean_cell(cell):
            cell_str = str(cell)
            for term in search_terms:
                if term in cell_str:
                    cell_str = cell_str.replace(term, "")
            return cell_str.strip()
        
        df = df.applymap(clean_cell)

    return df


def replace_chinese_symbols(df):#5
    # 定义中文符号和对应的英文符号
    replacements = {
        ',': ',',
        '。': '.',
        '!': '!',
        '?': '?',
        ':': ':',
        ';': ';',
        '(': '(',
        ')': ')',
        '【': '[',
        '】': ']',
        '《': '<',
        '》': '>',
        '、': ',',
        '——': '-'
    }

    def replace_symbols(cell):
        if pd.isna(cell) or cell == "":
            return cell  # 保持空白或 NaN

        if isinstance(cell, str):
            for ch, repl in replacements.items():
                cell = cell.replace(ch, repl)
        return cell

    df = df.applymap(replace_symbols)
    return df
	
def remove_duplicate_urls(df):
    list_columns(df)
    column_index = int(input("请输入要去重的列的标号: "))

    # 获取指定列的数据
    column_data = df.iloc[:, column_index]

    # 创建一个新的列表来存储处理后的数据
    cleaned_column = []
    seen = set()

    for cell in column_data:
        if pd.notna(cell):
            # 拆分内容为列表并去重
            urls = cell.split('; ')
            unique_urls = []
            for url in urls:
                if url not in seen:
                    seen.add(url)
                    unique_urls.append(url)
            # 如果该单元格中有唯一的URL,保留它们,否则置空
            if unique_urls:
                cleaned_column.append('; '.join(unique_urls))
            else:
                cleaned_column.append("")
        else:
            cleaned_column.append(cell)

    # 更新DataFrame的指定列
    df.iloc[:, column_index] = cleaned_column

    return df
	
def generate_sub_table_in_same_file(df, writer):
    list_columns(df)
    
    selected_columns = input("请输入要保留的列的标号(以空格分隔): ").split()
    selected_columns = [int(col) for col in selected_columns]

    # 添加是否进行筛选的选项
    apply_filter = input("是否要进行筛选? (y/n): ").strip().lower()

    if apply_filter == 'y':
        filter_column_index = int(input("请输入要根据哪列进行筛选的列标号: "))
        # 使用 fillna 将 NaN 替换为字符串标识符,以便用户选择
        unique_values = df.iloc[:, filter_column_index].fillna("空值").unique()

        print("筛选条件标号:")
        for i, value in enumerate(unique_values):
            print(f"{i}: {value}")
        condition_index = int(input("请输入筛选的条件标号: "))
        condition_value = unique_values[condition_index]

        # 选择筛选并删除还是筛选并保留
        filter_option = input("请选择操作: 1 - 筛选并删除, 2 - 筛选并保留: ").strip()

        # 处理筛选条件,包括空值
        if condition_value == "空值":
            mask = df.iloc[:, filter_column_index].isna()
        else:
            mask = df.iloc[:, filter_column_index] == condition_value

        if filter_option == '1':
            df_sub = df[~mask]
        elif filter_option == '2':
            df_sub = df[mask]
        else:
            print("无效选项,默认筛选并删除")
            df_sub = df[~mask]
    else:
        # 不进行筛选,直接保留所有行
        df_sub = df.copy()

    # 无论是否筛选,保留用户选择的列
    df_sub = df_sub.iloc[:, selected_columns]

    new_sheet_name = input("请输入新表的名称: ")
    df_sub.to_excel(writer, sheet_name=new_sheet_name, index=False)


def split_table_in_half(df, writer):
    # 计算总行数并计算出中点
    total_rows = len(df)
    midpoint = total_rows // 2
    
    # 确保第一部分和第二部分数据的数量
    first_half = df.iloc[:midpoint, :]
    second_half = df.iloc[midpoint:, :]

    # 获取用户输入的新表名称
    first_sheet_name = input("请输入第一部分表的名称: ")
    second_sheet_name = input("请输入第二部分表的名称: ")

    # 保存两部分数据到新的表中
    first_half.to_excel(writer, sheet_name=first_sheet_name, index=False)
    second_half.to_excel(writer, sheet_name=second_sheet_name, index=False)

    print(f"表已分割,并保存为 '{first_sheet_name}' 和 '{second_sheet_name}' 两个新表。")

def append_data_from_excel_b_to_a(df_a, df_b):
    # 获取A和B表的列名
    columns_a = df_a.columns
    columns_b = df_b.columns

    # 创建一个包含所有A表列的空值DataFrame
    empty_df = pd.DataFrame(columns=columns_a)

    # 遍历B表的列,如果列在A表中存在,则将数据添加到A表对应的列,否则添加空值列
    for col in columns_a:
        if col in columns_b:
            empty_df[col] = df_b[col]
        else:
            empty_df[col] = pd.NA  # 添加空值列

    # 将处理后的B表数据追加到A表
    df_a = pd.concat([df_a, empty_df], ignore_index=True)

    return df_a


def main():
    while True:
        file_path = input("请输入Excel文件路径: ")
        xls = pd.ExcelFile(file_path)
        
        # 如果文件中有多个表,让用户选择要使用的表
        if len(xls.sheet_names) > 1:
            print("请选择要使用的表:")
            for i, sheet_name in enumerate(xls.sheet_names):
                print(f"{i}: {sheet_name}")
            sheet_index = int(input("请输入表的标号: "))
            df = pd.read_excel(xls, sheet_name=xls.sheet_names[sheet_index])
        else:
            df = pd.read_excel(xls)

        with pd.ExcelWriter(file_path, mode='a', engine='openpyxl') as writer:
            print("\n请选择要执行的操作:")
            print("0: 用户添加")
            print("1: 列表删除")
            print("2: URL格式识别与删除")
            print("3: 对用户指定列筛选并删除筛出的行")
            print("4: 指定内容检索并删除")
            print("5: 替换所有中文符号为英文")
            print("6: 域名去重")
            print("7: 附表生成")
            print("8: 表格对半分割")

            choice = int(input("请输入选项: "))

            if choice == 0:
                file_b_path = input("请输入Excel B文件路径: ")
                df_b = pd.read_excel(file_b_path)
                df = append_data_from_excel_b_to_a(df, df_b)
            elif choice == 1:
                df = remove_columns_from_excel(df)
            elif choice == 2:
                df = clean_urls_in_column(df)
            elif choice == 3:
                df = filter_and_delete_rows(df)
            elif choice == 4:
                df = search_and_delete(df)
            elif choice == 5:
                df = replace_chinese_symbols(df)
            elif choice == 6:
                df = remove_duplicate_urls(df)
            elif choice == 7:
                generate_sub_table_in_same_file(df, writer)
            elif choice == 8:
                split_table_in_half(df, writer)
            else:
                print("无效选项")
                return

            if choice not in [7, 8]:
                # 生成新的文件名,如果存在同名文件则追加数字后缀
                base_name, ext = os.path.splitext(file_path)
                output_path = base_name + f'_output.xlsx'
                counter = 1
                while os.path.exists(output_path):
                    output_path = base_name + f'_output_{counter}.xlsx'
                    counter += 1

                df.to_excel(output_path, index=False)
                print(f"操作后的Excel文件已保存为: {output_path}")
        
        continue_choice = input("是否继续执行其他操作?(y/n): ").strip().lower()
        if continue_choice != 'y':
            print("程序结束。")
            break



if __name__ == "__main__":
    main()

  • 功能0:用户添加

使用场景,A表多个表头与参数,需向A表补充B表中记录的信息,且B表信息不一定全,B表中内容补充到A表末尾

  • 功能1:列表删除

使用场景:列出所有表头,按需求输入要保留的列名,其他的删除,且按照输入的列名顺序对剩下列排序

  • 功能2:URL格式识别与删除

适用场景:对指定列,进行url正则匹配,删除不是url格式的内容,并对只有域名的进行补充完整协议http://

  • 功能3:对用户指定列筛选并删除筛出的行

适用场景:列出所有列名,选择要筛的列,分类并列出对应列的内容,对指定内容进行删除(会删除整行数据)

  • 功能4: 指定内容检索并删除

使用场景:在表格中指定内容进行删选删除,一种为仅删除该内容,另一种为删除整行内容

  • 功能5: 替换所有中文符号为英文

使用场景:替换符号

  • 功能6: 域名去重

使用场景:去除某列中重复的域名

  • 功能7: 附表生成

使用场景:选择要保留的列,选择是要根据哪列进行筛选,是筛选并删除还是筛选并保留,之后生成一张新表。

  • 功能8: 表格对半分割

使用场景:对指定表格中的内容进行分割,方便后续处理

标签:index,报表,df,py,excel,cell,column,print,columns
From: https://www.cnblogs.com/daydaydream/p/18455995

相关文章

  • [Python手撕]第 k 个缺失的正整数
    给你一个严格升序排列的正整数数组arr和一个整数k。请你找到这个数组里第k个缺失的正整数。示例1:输入:arr=[2,3,4,7,11],k=5输出:9解释:缺失的正整数包括[1,5,6,8,9,10,12,13,...]。第5个缺失的正整数为9。示例2:输入:arr=[1,2,3,4],k=2输出:6解释:缺......
  • 基于Python后端构建多种不同的系统终端界面研究
    在我们一般开发系统的时候,往往会根据实际需要做出各种不同的系统终端界面,如基于BS的,CS、APP、小程序等等,一般都是基于一个统一接入的WebAPI后端,本篇系统探寻对基于Python后端构建多种不同的系统终端界面研究,介绍一些基于Python后端开发的不同终端界面。1、Python系统终端界面我......
  • 【2024版】最简单的Pycharm安装 教程(新手小白都能学会)
    PyCharm安装教程1、点击右边链接→PyCharm安装包我们以专业版为例,下载完成后打开安装包点击下一步先选择安装位置,然后点击下一步勾选所有选项,点击下一步直接点击安装等待安装完成激火后PyCharm就可以使用了PyCharm专业版安装包、集活码获取:点击这里最......
  • 最新毕设-Python-旅游数据分析与可视化系统-48196(免费领项目)可做计算机毕业设计JAVA、
    基于python的旅游数据分析与可视化系统的设计与实现摘 要本文旨在设计和实现一个基于Python的旅游数据分析可视化系统。该系统以旅游数据为研究对象,利用Python的数据处理能力和可视化技术,对旅游数据进行深入分析,并通过直观的可视化图表展示分析结果。本文首先介绍了旅游数......
  • python程序停到这个地方 client_socket, address = server_socket.accept()
    停到这个地方 client_socket,address=server_socket.accept() 这行代码是在等待客户端的连接请求。server_socket.accept()是一个阻塞调用,它会一直等待有客户端连接上来,然后返回一个新的套接字对象client_socket和客户端的地址address。如果你的程序在这一行停止,可能......
  • 用Python类实现装饰器
    用Python类实现装饰器为什么使用类实现装饰器?类装饰器的实现增加状态的类装饰器带参数的类装饰器为什么使用类实现装饰器?在某些情况下,我们可能希望装饰器保存状态、初始化一些参数,或者通过对象的方法操作。这时,用类实现装饰器会显得更为灵活和合理。类装饰器允许我们......
  • 深入理解 Python 中的 object
    深入理解Python中的object什么是object()?object()的作用和特点object是所有类的基类基础且不可变的对象object提供基本的对象行为object()作为占位符为什么要了解object?什么是object()?object()是Python的一个内置函数,它用于创建一个最基础的对象实例。......
  • Python 给函数加上状态的多种方式
    Python给函数加上状态的多种方式为什么要给函数加状态?方法一:使用函数属性方法二:使用闭包方法三:使用类方法四:使用装饰器为什么要给函数加状态?通常,函数是无状态的:每次调用它都会从相同的初始状态开始执行。而有时候,我们希望函数在多次调用之间能够保留某些信息,例如记......
  • python从0快速上手(二)IDE选择
    在这个代码横飞的世界里,选择一个合适的PythonIDE就好比是选择一把顺手的武器。今天,就让我来带你一探究竟,看看市面上有哪些让人眼花缭乱的PythonIDE,并一较高下。1.PyCharmPyCharm,由大名鼎鼎的JetBrains出品,是Python开发者中的宠儿。它以其强大的代码分析和智能提示功能......
  • 4.文件规划:让你的Python更加简洁
    在上一篇文章之中,小编简单的介绍了目前Python中主流的三大Web框架,分别是Django、Flask和FastAPI,并且介绍了它们的优缺点。并且,我们快速的使用FastAPI搭建了一个简单的RestFul风格的接口,并且使用unicorn作为Web服务器,来向外提供服务。最后,我们使用我们学习到的FastAPI知识,......