Python脚本使用说明:从CSV提取指定列数据

脚本目标

本Python脚本旨在帮助您从CSV(逗号分隔值)文件中提取特定列的数据。您可以指定要提取哪一列,是否跳过CSV文件的第一行(通常是表头),并且可以选择输出所有行、前N行、后N行或指定范围的行。所有最终输出的数据都将是字符串格式,并以元组(tuple)的形式呈现,例如 ('数据1', '数据2', '数据3')

如何使用

  1. 保存脚本

    • 将之前提供的最新Python代码复制到一个文本文件中。
    • 将该文件保存为 .py 结尾的Python文件,例如 extract_csv_column_v2.py
  2. 准备您的CSV文件

    • 确保您知道要处理的CSV文件的完整路径(例如 C:\Users\您的用户名\Documents\data.csv 或者 /home/user/data.csv)。
    • 确认您要提取的是第几列的数据。
  3. 运行脚本

    • 打开您的计算机的终端(在Windows上可能是命令提示符 cmd 或 PowerShell,在macOS或Linux上是 Terminal)。
    • 使用 cd 命令切换到您保存Python脚本的目录。例如,如果您保存在 Documents 文件夹下,可以输入:
      cd Documents
      
    • 然后运行脚本,输入:
      python extract_csv_column_v2.py
      
      (请将 extract_csv_column_v2.py 替换为您实际保存的文件名)。
  4. 按照提示操作
    脚本运行时,会依次向您提问:

    • "请输入您的CSV文件路径 (Enter the path to your CSV file):"

      • 在这里输入您的CSV文件的完整路径,然后按回车键。
      • 示例:my_data.csv (如果文件在脚本同一目录下) 或 /path/to/your/file.csv
    • "请输入要提取的列号 (例如,1代表第一列) (Enter the column number to extract, e.g., 1 for the first column):"

      • 输入您想要提取数据的是第几列。请注意,这里的列号是从 1 开始计数的。例如,要提取第一列,请输入 1;要提取第二列,请输入 2,以此类推。然后按回车键。
    • "您的CSV文件是否有需要跳过的表头行? (yes/no) (Does your CSV file have a header row to skip? (yes/no)):"

      • 如果您的CSV文件的第一行是列名或标题(即表头),并且您不希望将表头包含在最终的输出数据中,请输入 yesy
      • 如果您的CSV文件没有表头,或者您希望将第一行也作为数据提取出来,请输入 non
      • 然后按回车键。
    • 行选择选项提示
      脚本会显示以下行选择选项:

      行选择选项 (Row selection options):
      1. 所有行 (All rows - default)
      2. 前 N 行 (First N rows)
      3. 后 N 行 (Last N rows)
      4. 指定范围的行 (e.g., 100-500) (A specific range of rows)
      
      • "请选择行选择选项 (1/2/3/4,或直接按 Enter 选择 '所有行'):"
        • 输入选项编号 (1, 2, 3, 4) 或直接按 Enter 键选择默认的“所有行”。
    • 根据行选择的进一步提示

      • 如果选择 1 (所有行) 或直接按 Enter:不会有更多关于行选择的提问。
      • 如果选择 2 (前 N 行)
        • 会提示:"请输入要提取的前 N 行中的 N 值:"
        • 输入一个正整数 N。
      • 如果选择 3 (后 N 行)
        • 会提示:"请输入要提取的后 N 行中的 N 值:"
        • 输入一个正整数 N。
      • 如果选择 4 (指定范围的行)
        • 会提示(提示文本会根据您之前是否选择跳过表头而略有不同):
          • (如果不跳过表头): "请输入行范围 (例如 100-500,1基准,包含首尾):"
          • (如果跳过表头): "请输入数据行范围 (例如 100-500,1基准,包含首尾,指跳过表头后的数据行):"
        • 输入行范围,格式为 开始行-结束行 (例如 100-500)。这里的行号是 1基准 的,并且 包含 开始行和结束行。
        • 重要:如果选择了跳过表头,那么这里输入的行号指的是数据行的行号(即表头之后的第一行数据为第1行,第二行数据为第2行,以此类推)。
  5. 查看输出

    • 脚本会读取CSV文件,根据您的选择处理数据,然后会在终端打印出提取到的数据。
    • 输出的格式将是一个元组 (tuple),其中每个元素都是字符串类型。例如:
      提取的数据 (元组格式,所有元素为字符串):
      (Extracted data as a tuple of strings):
      ('144173556479295488', '144173858159984640', '144190726925385728')
      
      或者,如果提取的是文本:
      提取的数据 (元组格式,所有元素为字符串):
      (Extracted data as a tuple of strings):
      ('张三', '李四', '王五')
      

注意事项与错误处理


脚本Python代码:

import csv

def extract_column_to_tuple_of_strings():
    """
    Prompts the user for CSV file details, extracts a specified column
    with options to limit rows, and prints it as a tuple of strings.
    """
    file_path = input("请输入您的CSV文件路径 (Enter the path to your CSV file): ")
    
    while True:
        try:
            column_input_str = input("请输入要提取的列号 (例如,1代表第一列) (Enter the column number to extract, e.g., 1 for the first column): ")
            column_index = int(column_input_str) - 1 
            if column_index < 0:
                print("列号必须是大于等于1的整数。请重新输入。(Column number must be 1 or greater. Please try again.)")
                continue
            break
        except ValueError:
            print("输入无效。请输入一个整数作为列号。(Invalid input. Please enter a whole number for the column.)")

    skip_header = False
    while True:
        include_header_str = input("您的CSV文件是否有需要跳过的表头行? (yes/no) (Does your CSV file have a header row to skip? (yes/no)): ").lower()
        if include_header_str in ['yes', 'y']:
            skip_header = True
            break
        elif include_header_str in ['no', 'n']:
            skip_header = False
            break
        else:
            print("输入无效。请输入 'yes' 或 'no'。(Invalid input. Please enter 'yes' or 'no'.)")

    # 行选择逻辑
    row_limit_mode = "all"
    limit_n = 0
    limit_start_row = 0  # 1-based for user input
    limit_end_row = 0    # 1-based for user input

    print("\n行选择选项 (Row selection options):")
    print("1. 所有行 (All rows - default)")
    print("2. 前 N 行 (First N rows)")
    print("3. 后 N 行 (Last N rows)")
    print("4. 指定范围的行 (e.g., 100-500) (A specific range of rows)")
    
    while True:
        choice = input("请选择行选择选项 (1/2/3/4,或直接按 Enter 选择 '所有行'): ").strip().lower()
        if choice == '1' or choice == 'all' or not choice:
            row_limit_mode = "all"
            break
        elif choice == '2' or choice == 'first':
            row_limit_mode = "first"
            while True:
                try:
                    limit_n_str = input("请输入要提取的前 N 行中的 N 值: ")
                    limit_n = int(limit_n_str)
                    if limit_n <= 0:
                        print("N 必须是一个正整数。(N must be a positive integer.)")
                        continue
                    break
                except ValueError:
                    print("输入无效。请输入一个整数作为 N 值。(Invalid input. Please enter a whole number for N.)")
            break
        elif choice == '3' or choice == 'last':
            row_limit_mode = "last"
            while True:
                try:
                    limit_n_str = input("请输入要提取的后 N 行中的 N 值: ")
                    limit_n = int(limit_n_str)
                    if limit_n <= 0:
                        print("N 必须是一个正整数。(N must be a positive integer.)")
                        continue
                    break
                except ValueError:
                    print("输入无效。请输入一个整数作为 N 值。(Invalid input. Please enter a whole number for N.)")
            break
        elif choice == '4' or choice == 'range':
            row_limit_mode = "range"
            range_prompt = "请输入行范围 (例如 100-500,1基准,包含首尾): "
            if skip_header:
                range_prompt = "请输入数据行范围 (例如 100-500,1基准,包含首尾,指跳过表头后的数据行): "
            
            while True:
                try:
                    range_str = input(range_prompt)
                    parts = range_str.split('-')
                    if len(parts) != 2:
                        raise ValueError("范围必须是 '开始行-结束行' 的格式。(Range must be in format start-end.)")
                    limit_start_row = int(parts[0].strip())
                    limit_end_row = int(parts[1].strip())
                    
                    if limit_start_row <= 0 or limit_end_row <= 0:
                        print("行号必须是正整数。(Row numbers must be positive.)")
                        continue
                    if limit_start_row > limit_end_row:
                        print("开始行号不能大于结束行号。(Start row cannot be greater than end row.)")
                        continue
                    break
                except ValueError as e:
                    print(f"输入无效: {e} 请使用 '开始行-结束行' 格式并输入数字 (e.g., 100-500)。(Invalid input: {e}. Please use format 'start-end' with numbers (e.g., 100-500).)")
            break
        else:
            print("选择无效。请输入 1, 2, 3, 4, 或 'all' (或直接按 Enter)。(Invalid choice. Please enter 1, 2, 3, 4, or 'all' (or press Enter).)")

    all_column_data = []
    try:
        with open(file_path, mode='r', newline='', encoding='utf-8') as csvfile:
            reader = csv.reader(csvfile)
            
            header_skipped_once = False
            if skip_header:
                try:
                    next(reader)  # 跳过表头行
                    header_skipped_once = True
                except StopIteration:
                    print("警告: CSV文件为空或仅包含表头。(Warning: CSV file is empty or only contains a header.)")

            # 读取指定列的所有(潜在)数据行
            for row in reader:
                current_csv_line_num = reader.line_num # 获取当前在CSV文件中的物理行号
                try:
                    all_column_data.append(str(row[column_index]))
                except IndexError:
                    # column_input_str 是用户输入的1基准列号
                    print(f"警告: CSV文件第 {current_csv_line_num} 行, 内容 '{','.join(row)}', 对于列号 {column_input_str} 来说太短。将为此项使用空字符串。")
                    print(f"(Warning: CSV line {current_csv_line_num}, Row content '{','.join(row)}', is too short for column index {column_input_str}. Using empty string for this item.)")
                    all_column_data.append('') # 如果行太短,添加空字符串

        # 根据用户的选择应用行限制
        final_data_to_output = []
        if not all_column_data:
            if not header_skipped_once and skip_header: # 文件是空的,并且尝试跳过表头但失败了
                 pass # 警告已在上面打印
            elif header_skipped_once and not all_column_data: # 文件只有表头
                 print("在跳过表头后,指定列没有数据。(No data found in the specified column after skipping the header.)")
            else: # 文件本身就没数据(或者指定列没数据,但通常是前者)
                 print("在指定列或文件中未找到数据。(No data found in the specified column or file.)")
        elif row_limit_mode == "all":
            final_data_to_output = all_column_data
        elif row_limit_mode == "first":
            final_data_to_output = all_column_data[:limit_n]
        elif row_limit_mode == "last":
            final_data_to_output = all_column_data[-limit_n:]
        elif row_limit_mode == "range":
            # 用户输入的 limit_start_row 和 limit_end_row 是1基准的
            # Python列表切片是0基准的,且不包含尾部索引
            # 所以,[M-1 : N] 会提取第 M 项到第 N 项
            start_idx = limit_start_row - 1
            end_idx = limit_end_row 
            
            if start_idx >= len(all_column_data):
                print(f"警告: 开始行 {limit_start_row} 超出了数据总行数 ({len(all_column_data)} 行)。输出将为空。")
                print(f"(Warning: Start row {limit_start_row} is beyond the end of the data ({len(all_column_data)} data rows). Output will be empty.)")
                final_data_to_output = []
            else:
                final_data_to_output = all_column_data[start_idx:end_idx]
                if not final_data_to_output and start_idx < end_idx: # 检查范围是否有效但结果为空
                     # 例如,数据共5行,用户请求6-10行
                     if start_idx < len(all_column_data) and end_idx > len(all_column_data):
                          print(f"警告: 指定范围 {limit_start_row}-{limit_end_row} 部分超出数据行 ({len(all_column_data)} 行),仅输出范围内有效部分。")
                     elif start_idx >= len(all_column_data): # 这种情况已在上面处理
                          pass
                     else: # 例如,请求 100-200 行,但数据只有 50 行
                          print(f"警告: 指定范围 {limit_start_row}-{limit_end_row} 没有从可用的 {len(all_column_data)} 数据行中获取到数据。")
                          print(f"(Warning: The specified range {limit_start_row}-{limit_end_row} resulted in no data from the available {len(all_column_data)} data rows.)")


        output_tuple = tuple(final_data_to_output)
        print("\n提取的数据 (元组格式,所有元素为字符串):")
        print("(Extracted data as a tuple of strings):")
        print(output_tuple)

    except FileNotFoundError:
        print(f"错误: 文件 '{file_path}' 未找到。(Error: The file '{file_path}' was not found.)")
    except Exception as e:
        print(f"发生未知错误: {e} (An unexpected error occurred: {e})")

if __name__ == "__main__":
    extract_column_to_tuple_of_strings()