# 关于表格

  • 键值对形式的数据,符合程序员的阅读习惯。但普通人,更习惯阅读表格形式的数据。

# 表格分类

  • 在计算机中编辑表格时,普通人通常会使用 Microsoft 公司的 Excel 软件。这种软件保存的表格文件,扩展名通常为 .xlsx 。

    • 优点:
      • Excel 不止提供了编辑表格这一基础功能,还提供了绘制图表、公式运算等功能,满足用户的各种使用需求。
    • 缺点:
      • .xlsx 文件通常只能被 Excel 软件打开、编辑,而 Excel 是一款付费软件。因此,如果人们普遍使用 .xlsx 文件,就意味着每个人都要购买 Excel 软件的使用权。
      • Python 安装 openpyxl 等专业的第三方库,才能解读 .xlsx 文件的内容。否则,直接用 open() 打开 .xlsx 文件,只能看到 bytes 格式的数据,不能解读。
  • 除了 .xlsx 文件之外,还有一种常见的表格文件,扩展名为 .csv 。它采用 CSV(Comma Separated Values)格式。

    • 优点:
      • 格式简单。只需要在相邻字段之间,插入一个英文逗号,作为分隔符。
      • 通用性强,可以被大部分软件打开、编辑。
        • 例如 Python 可以直接用 open() 打开、编辑 .csv 文件。不过推荐使用 csv 标准库,更方便。
    • 缺点:
      • 只能实现编辑表格这一基础功能。
  • 用 Excel 软件也可以打开 .csv 文件,还可以将 .xlsx 文件保存为 .csv 文件。

    • 当 .csv 文件符合以下格式时,它在 Excel 软件中显示的内容,才会与 .xlsx 文件一致。
      • 每行的相邻字段之间,插入一个英文逗号,作为分隔符。
      • 每行文本的换行符为 '\r\n' 。
      • 单个字段中,如果包含英文逗号、英文双引号,则要在每个双引号之前添加一个双引号进行转义,还要用一对双引号将这个字段包住,从而避免被识别为多个字段。
    • 例:用 Excel 编辑 .xlsx 文件,写入如下三个单元格:
      AB    A,B    A"B
      
      用 Excel 将它保存为 .csv 文件,然后用 Python 读取该 .csv 文件,可见它内容如下:
      >>> with open('test.csv', newline='') as f:   # 这里设置 newline='' 是为了避免自动替换换行符,从而保留原始的换行符
      ...     f.read()
      ...
      'AB,"A,B","A""B"\r\n'
      

# import csv

:Python 的标准库,用于读写 csv 文件。

  • 官方文档 (opens new window)

  • 例:写入 .csv 表格

    >>> import csv
    >>> with open('test.csv', 'w', newline='') as f:
    ...     writer = csv.writer(f)    # 针对文件对象 f ,创建一个 csv 写入器
    ...     writer.writerow('hello')  # 写入表格的一行内容。该方法要求输入一个可迭代对象,将其中每个元素写作一个字段
    ...     writer.writerows('world') # 写入表格的多行内容。该方法要求输入一个可迭代对象,对其中每个元素执行一次 writerow()
    ...
    11
    
    • 检查写入 .csv 文件的内容:
      >>> with open('test.csv') as f:
      ...     f.read()
      ...
      'h,e,l,l,o\nw\no\nr\nl\nd\n'
      
  • 例:读取 .csv 表格:

    >>> with open('test.csv', 'r') as f:
    ...     reader = csv.reader(f)  # 针对文件对象 f ,创建一个 csv 阅读器
    ...     headers = next(reader)  # 读取表格的第一行内容
    ...     print(headers)
    ...     for line in reader:     # 每次迭代,获取表格的一行内容
    ...         print(line)
    ...
    ['h', 'e', 'l', 'l', 'o']
    ['w']
    ['o']
    ['r']
    ['l']
    ['d']
    
    • 除了文件对象,针对其它可迭代对象,也可以创建 csv 阅读器。
      >>> data = ['a,b,c\n', '1,2,3']
      >>> [i for i in csv.reader(data)]
      [['a', 'b', 'c'], ['1', '2', '3']]
      
  • CSV 文本格式没有严格的标准,存在多种方言(或者说风格)。

    • 常见的几种方言如下:
      >>> csv.list_dialects()
      ['excel', 'excel-tab', 'unix']
      
    • csv.reader() 和 csv.writer() 默认采用 dialect='excel' ,其定义如下:
      class excel(Dialect):
          delimiter = ','           # 相邻字段之间的分隔符
          quotechar = '"'           # 单个字段的定界符,避免单个字段被识别为多个字段
          doublequote = True        # 添加 quotechar 时,是否在当前字段的前后都加上 quotechar ,还是只在前面加上 quotechar
          skipinitialspace = False  # 是否忽略 delimiter 之后的空格
          lineterminator = '\r\n'   # 换行符
          quoting = QUOTE_MINIMAL   # 何时添加 quotechar 。QUOTE_ALL 表示总是添加。QUOTE_MINIMAL 表示尽量不添加,除非字段包含特殊字符
      
      • 改成 delimiter = '\t' ,就变成了 dialect='excel-tab' 方言。
      • 改成 lineterminator = '\n'quoting = QUOTE_ALL ,就变成了 dialect='unix' 方言。
    • 例:自定义一种方言
      >>> class myDialect(csv.excel):
      ...     delimiter = '|'
      ...
      >>> csv.register_dialect('myDialect', myDialect)    # 注册 dialect
      >>> with open('test.csv', 'w', newline='') as f:
      ...     writer = csv.writer(f, dialect='myDialect') # 采用 dialect
      ...     writer.writerow('hello')
      ...
      

# import openpyxl

:Python 的第三方库,用于读写 Excel 2010 软件生成的表格文件,扩展名通常为 .xlsx 或 .xlsm 。

# Workbook

  • 在 Excel 软件中,一个 .xlsx 文件,负责存储一个工作簿(Workbook)。

    • 一个 Workbook 包含任意个工作表(Worksheet)。
    • 每个 Worksheet 包含任意个单元格(cell)。这些单元格呈矩形排列,分为多行(row)、多列(column)。
  • 例:创建表格

    >>> from openpyxl import Workbook
    >>> wb = Workbook()                   # 创建一个 Workbook 对象
    >>> wb.sheetnames                     # 列出所有 Worksheet 的名称。新创建的 Workbook 只包含一个 Worksheet
    ['Sheet']
    >>> ws = wb.create_sheet('Sheet1', 0) # 插入一个新的 Worksheet ,放在位置 0 处。如果不指定位置,则默认放在最后
    >>> ws.title = 'Sheet1'               # 修改 Worksheet 的名称
    >>> wb.save('1.xlsx')                 # 将 Workbook 保存为一个 .xlsx 文件
    
  • 例:打开表格

    >>> from openpyxl import load_workbook
    >>> wb = load_workbook('1.xlsx')
    >>> wb.sheetnames
    ['Sheet1', 'Sheet']
    >>> ws = wb['Sheet1'] # 选择一个 Worksheet
    >>> ws
    <Worksheet "Sheet1">
    
    • 如果以只读模式打开 .xlsx 文件,则可以大幅减少内存开销:
      >>> wb = load_workbook('1.xlsx', read_only=True)
      >>> wb.close()  # 只读模式下,需要手动关闭对文件描述符的占用
      
    • 或者通过 open() 打开文件,载入内存:
      import io
      with open('1.xlsx', 'rb') as f:
          in_mem_file = io.BytesIO(f.read())
      
      wb = load_workbook(in_mem_file, read_only=True)
      
  • 例:修改表格

    >>> ws.max_row        # 查询 Worksheet 的最大行数
    1
    >>> ws.max_column     # 查询 Worksheet 的最大列数
    1
    >>> ws.column_dimensions['A'].width = 20.0  # 设置列宽
    >>> ws.row_dimensions[1].height = 20.0      # 设置行高
    

# Cell

  • 例:插入一行单元格

    >>> ws.append([1, 2, 3])  # 在 Worksheet 末尾追加一行。要求输入一个可迭代对象,将其中每个元素保存为该行的一个单元格
    >>> ws.append([4, 5, 6])
    >>> ws.append([7, 8, 9])
    
  • 例:遍历单元格

    >>> for row in ws:    # 遍历 Worksheet 的每行,每行由多个 cell 组成
    ...     print(row)
    ...
    (<Cell 'Sheet1'.A1>, <Cell 'Sheet1'.B1>, <Cell 'Sheet1'.C1>)
    (<Cell 'Sheet1'.A2>, <Cell 'Sheet1'.B2>, <Cell 'Sheet1'.C2>)
    (<Cell 'Sheet1'.A3>, <Cell 'Sheet1'.B3>, <Cell 'Sheet1'.C3>)
    
  • 例:获取指定位置的单元格

    >>> ws.cell(row=1, column=1)  # 通过行号、列号,获取一个 cell 。两种编号都是从 1 开始递增
    <Cell 'Sheet1'.A1>
    >>> ws['A1']          # 通过索引,获取第 A 列、第 1 行的那个 cell
    <Cell 'Sheet1'.A1>
    >>> ws['A']           # 获取第 A 列,所有不为空的 cell
    (<Cell 'Sheet1'.A1>, <Cell 'Sheet1'.A2>, <Cell 'Sheet1'.A3>)
    >>> ws['1']           # 获取第 1 行,所有不为空的 cell
    (<Cell 'Sheet1'.A1>, <Cell 'Sheet1'.B1>, <Cell 'Sheet1'.C1>)
    >>> ws['A1':'B2']     # 通过切片,获取矩形范围内的一组 cell
    ((<Cell 'Sheet1'.A1>, <Cell 'Sheet1'.B1>), (<Cell 'Sheet1'.A2>, <Cell 'Sheet1'.B2>))
    
  • 例:对单元格进行赋值

    >>> ws['A1'] = 'hello'  # 对 cell 赋值
    >>> ws['A1'].value      # 读取 cell 的值
    'hello'
    >>> ws['A10'].value     # 可以读取任意 cell 的值,如果取值为空,则返回 None
    >>> ws['C4'] = '=SUM(A1:C3)'  # 给 cell 赋值时,可以输入 Excel 的公式
    
  • 关于坐标:

    >>> ws['A1'].coordinate     # 完整坐标
    'A1'
    >>> ws['A1'].row            # 行坐标
    1
    >>> ws['A1'].column         # 列坐标,用数字表示
    1
    >>> ws['A1'].column_letter  # 列坐标,用字母表示
    'A'
    
    >>> from openpyxl.utils import get_column_letter, column_index_from_string
    >>> get_column_letter(2)    # 将列坐标,从数字转换成字母
    'B'
    >>> column_index_from_string('AA')  # 将列坐标,从字母转换成数字
    27
    
  • 关于字体:

    >>> cell.font.name  # 查看当前字体
    'Calibri'
    >>> cell.font.sz
    2.0
    
    from openpyxl.styles import Font
    font1 = Font(name='Calibri',   # 字体
                size=2.0,          # 字号
                bold=False,        # 加粗
                italic=False,      # 斜体
                underline='None',  # 下划线
                color='FF000000'   # 字体颜色
                ...)
    cell.Font = font1 # 设置字体