使用python讀Excel文件并寫入另一個xls模版

效果如下:

原文件內容

轉化后的內容

大致代碼如下:

1. load_it.py

#!/usr/bin/env python
import re
from datetime import datetime
from io import BytesIO
from pathlib import Path
from typing import List, Unionfrom fastapi import HTTPException
from openpyxl import load_workbookRE_SPACES = re.compile(r"\s{2,}")def slim(s: str) -> str:return RE_SPACES.sub(" ", s)class ValidationError(HTTPException):def __init__(self, detail: str, status_code: int = 400):super().__init__(status_code, detail=detail)def remove_author(s: str) -> str:if s := s.replace("作者:\n", "").replace("Administrator:\n", ""):return str(s)return ''def read_excel(filename: Union[Path, str, bytes, BytesIO]):if isinstance(filename, bytes):filename = BytesIO(filename)return load_workbook(filename)def load(filename: Union[Path, str, bytes, BytesIO]):wb = read_excel(filename)sheet_name = "工資表"try:sheet = wb[sheet_name]except KeyError:try:sheet = wb["Sheet1"]except KeyError:raise ValidationError(f"未找到名稱為{sheet_name!r}的工作表")title = sheet.cell(1, 1).value.strip()now = datetime.now()if "月" in title:remark = title.split("年")[-1].strip("表").replace("份", "")else:if (month := now.month - 1) == 0:month = 12remark = f"{month}月工資"day = f"{now:%Y.%m.%d}"lines: List[list] = []for row in range(4, sheet.max_row):xuhao = sheet.cell(row, 1).valueif xuhao and (isinstance(xuhao, int) or xuhao.isdigit()):name = sheet.cell(row, 2).valuetotal = 0if (base := sheet.cell(row, 4).value) is None:base = "/"else:if isinstance(base, str):if base.startswith("="):base = eval(base[1:])else:raise TypeError(f"Expect int value, got: {base=}")total += basecommission_comment = ""  # 提成批注commission_cell = sheet.cell(row, 5)if (commission := commission_cell.value) is None:commission = "/"else:if isinstance(commission, str) and commission.startswith('='):commission = eval(commission[1:])total += commissionif _cc := commission_cell.comment:if _ct := _cc.text:commission_comment = remove_author(_ct)if (attend := sheet.cell(row, 6).value) is None:if (attend := sheet.cell(row, 13).value) is None:attend = "/"if (attend_money := sheet.cell(row, 7).value) is not None:total += attend_moneyattend = attend.strip().strip("+-/").strip()if attend_money > 0:attend += f" +{attend_money}"else:attend += f" {attend_money}"if (late := sheet.cell(row, 8).value) is None:late = "/"else:late = slim(late)if late_money := sheet.cell(row, 9).value:total += late_moneyif late_money > 0:late = f"{late}{late_money}"else:late = late.strip("/") + str(late_money)if subsidy_value := sheet.cell(row, 11).value:  # 補助if isinstance(subsidy_value, str) and subsidy_value.startswith("="):subsidy_value = eval(subsidy_value[1:])try:total += subsidy_valueexcept TypeError:raise ValidationError(f"第{row}行第11列數據異常:預期為數值,得到的是{subsidy_value!r}")subsidy = "/"if _c := sheet.cell(row, 10).comment:if _s := _c.text:subsidy = remove_author(_s)one = [name,base,commission,attend,late,subsidy,total,remark,day,commission_comment,]lines.append(one)return linesdef main():import sysif not sys.argv[1:]:print("No args, do nothing.")returnprint(load(sys.argv[1]))if __name__ == "__main__":main()

?

?2. gen_excel.py

#!/usr/bin/env python
from datetime import datetime
from pathlib import Path
from typing import List, Optional, Tuple, Unionimport xlrd
import xlwt
from xlutils.copy import copy as xls_copyfrom load_it import load, read_excel, remove_author
from settings import BASE_DIR, MEDIA_ROOTSAMPLE = "salary_tips.xls"
DataType = Union[int, float, str, None]def cell_style(is_top: bool = False, is_bottom: bool = False, has_border=True):"""單元格樣式"""style = xlwt.XFStyle()# 字體大小,11為字號,20為衡量單位# font = xlwt.Font()style.font.height = 20 * 9align = xlwt.Alignment()# 0x01(左端對齊)、0x02(水平方向上居中對齊)、0x03(右端對齊)align.horz = 0x02# 0x00(上端對齊)、 0x01(垂直方向上居中對齊)、0x02(底端對齊)align.vert = 0x01# 設置自動換行align.wrap = 1style.alignment = align# 設置邊框# 細實線:1,小粗實線:2,細虛線:3,中細虛線:4,大粗實線:5,雙線:6,細點虛線:7# 大粗虛線:8,細點劃線:9,粗點劃線:10,細雙點劃線:11,粗雙點劃線:12,斜點劃線:13if has_border:borders = xlwt.Borders()borders.left = 2borders.right = 2borders.top = 1 + is_topborders.bottom = 1 + is_bottomstyle.borders = bordersreturn styledef boom(tips: List[List[Tuple[int, int, DataType]]]) -> str:"""將數據填入模板生成Excel表"""sample = BASE_DIR / SAMPLExls = xls_copy(xlrd.open_workbook(sample, formatting_info=True))ws = xls.get_sheet(0)style = cell_style()top_style = cell_style(is_top=True)bottom_style = cell_style(is_bottom=True)plain_style = cell_style(has_border=False)last_index = 8for datas in tips:for i, d in enumerate(datas[:-1]):if i == 0:ws.write(*d, top_style)elif i == last_index:ws.write(*d, bottom_style)else:ws.write(*d, style)if _tc := datas[-1]:row, col, text = _tcif text:ws.write_merge(row, row, col - 1, col, text, plain_style)fname = MEDIA_ROOT / f"gzt_{datetime.now():%Y%m%d%H%M%S}.xls"try:xls.save(fname)except TypeError as e:print("May be you can look at this to fix it:")print("https://blog.csdn.net/zhangvalue/article/details/105170305")raise ereturn str(fname).replace(str(BASE_DIR), "")  # 返回相對路徑def build_tips(lines: List[List[DataType]]):row_delta = 10  # 每隔10行填下一排的數據col_delta = 3  # 每隔3列填下一組數據line_tip = 5  # 每行有5個工資條row_begin = 0  # 從第一行開始col_begin = 1  # 從第二列開始填數據(第一列是固定的表頭)tips = []for tip_index, tip in enumerate(lines):first_row = row_begin + tip_index // line_tip * row_deltacol_index = col_begin + tip_index % line_tip * col_deltad = [(row_index + first_row, col_index, value)for row_index, value in enumerate(tip)]tips.append(d)return tipsdef burn_life(content: bytes) -> str:return boom(build_tips(load(content)))def dear_sister(content: bytes, origin_name: Optional[str] = None) -> str:"""2022-04-04 親愛的妹妹想要一個可以把批注提取出來的"""wb = read_excel(content)sheet = wb.worksheets[0]count = 0# openpyxl的行和列都是從1開始for row in range(1, sheet.max_row):for col in range(1, sheet.max_column):cell = sheet.cell(row, col)if comment := cell.comment:if text := comment.text:cell.value = remove_author(text)count += 1if origin_name:fname = MEDIA_ROOT / f"{Path(origin_name).stem}-批注提取{count}.xls"else:fname = MEDIA_ROOT / f"批注提取{count}.xls"wb.save(fname)return str(fname).replace(str(BASE_DIR), "")  # 返回相對路徑def main():import sysif not sys.argv[1:]:print("No args, do nothing.")returnif (p := Path(sys.argv[1])).is_file():lines = load(p.read_bytes())else:day = f"{datetime.now():%Y.%m.%d}"ss = ["狄仁杰",1600,360,"休5天,請假7.5天 -400","遲到3次共16分鐘","扣社保-373\n工齡+100\n漏刷卡6次-300",987,"12月工資",day,]lines = [ss, ss]print(boom(build_tips(lines)))if __name__ == "__main__":main()

? ??

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/40356.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/40356.shtml
英文地址,請注明出處:http://en.pswp.cn/news/40356.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

睿趣科技:抖音開網店現在做還來得及嗎

隨著社交媒體的迅速發展,抖音作為一款短視頻平臺,已經在年輕人中間取得了巨大的成功。而近年來,越來越多的人開始考慮在抖音上開設網店,以迎合這一潮流。那么,抖音開網店現在還來得及嗎? 首先,要明確的是&…

一篇文章教會你搭建私人kindle圖書館,并內網穿透實現公網訪問

搭建私人kindle圖書館,并內網穿透實現公網訪問 在電子書風靡的時期,大部分人都購買了一本電子書,雖然這本電子書更多的時候是被擱置在儲物架上吃灰,或者成為蓋泡面的神器,但當亞馬遜發布消息將放棄電子書在中國的服務…

Kubernetes部署Wordpress時碰到的兩個問題解決

文章目錄 小結問題1解決問題2解決參考 小結 在使用Kubernetes部署Wordpress時返回了兩個問題: Function not implemented: AH00141: Could not initialize random number generator chown: changing ownership of .: Operation not permitted 對這個兩個返回錯誤&#xff0…

利用Python隧道爬蟲ip輕松構建全局爬蟲網絡

嘿,爬蟲程序員們!你們有沒有碰到過需要大規模數據爬取的情況?也許你們之前遇到過網站的反爬措施,卡住你們的進度。別擔心,今天我來分享一個利用Python隧道爬蟲ip實現的方法,幫助你們輕松搭建全局爬蟲ip網絡…

jmeter界面設置為中文

jmeter版本:5.6.2 找到jmeter下的bin目錄,打開jmeter.properties 文件 第39行修改為 languagezh_CN去掉前面的#,以后打開就是中文界面了

IC設計仿真云架構

對于IC仿真來說,最重要的是要安全、可維護、高性能的的HPC環境環境。 那么云上如何搭建起一套完整的IC仿真云環境呢? 這種架構應該長什么樣子? 桌面虛擬化基礎架構 將所有桌面虛擬機在數據中心進行托管并統一管理;同時用戶能夠…

RxJava 復刻簡版之三,map 多次中轉數據

案例代碼:https://gitee.com/bobidali/lite-rx-java/commit/292e9227a5491f7ec6a07f395292ef8e6ff69290 RxJava 的調用第一步是封裝了觀察者接受了數據的處理,進一步就是使用 map 將數據操作傳遞給上下游 1、類似Observer.create 創建一個簡單的觀察者…

神經網絡基礎-神經網絡補充概念-05-導數

概念 導數是微積分中的一個概念,用于描述函數在某一點的變化率。在數學中,函數的導數表示函數值隨著自變量的微小變化而產生的變化量,即斜率或變化率。 假設有一個函數 f(x),其中 x 是自變量,y f(x) 是因變量。函數…

如何評價機械革命?

機械革命是在全球頂尖IT廠商藍天、intel、nvidia、Microsoft等聯手的打造下推出的中高端品牌。(零件組裝) 機械革命研發實力雄厚,糟糕的外觀設計和極致的游戲性能一樣出名。圖片皆來自于未來世界。

【0214】postgres后端進程session退出,如何通過日志分析其會話信息

文章目錄 1. postgres進程session退出2. 開啟日志記錄postgres進程會話狀態3. postgres進程會話結束,記錄日志的實現原理1. postgres進程session退出 默認情況下,新建一個postgres后端進程會話(session),或是postgres進程正常/異常退出時,日志中沒有很明顯的記錄用于說明…

嵌入式:ARM Day4

一、自己編寫代碼實現三盞燈點亮 源碼: .text .global _start _start: 進行一次初始化bl RCC_INITbl LED1_INITbl LED2_INITbl LED3_INITb looploop: 循環開關燈bl LED1_ONbl delay_1sbl LED1_OFFbl delay_1sbl LED2_ONbl delay_1sbl LED2_OFFbl delay_1sbl…

如何進行網絡活動監控

組織的 IT 基礎架構中的每個網絡設備上都發生了大量活動,例如數據包傳輸、來自網絡協議的消息、設備狀態事件等。網絡活動成為在檢測到問題時識別網絡瓶頸的面包屑,因此即使是最微小的網絡活動也應受到監控,因為它直接影響整體網絡性能、運行…

UI設計師個人工作總結范文精選

UI設計師個人工作總結范文(一) 在忙忙碌碌中,2019年又將過去了,在這一年當中,設計部無論是在運作模式、設計產值、還是人員結構,各方面的變化都比較大。 設計部的運作模式是從7月底開始進行調整的,以獨立承包制的運營方…

爬蟲抓取數據時顯示超時,是代理IP質量不行?

很多人在做數據抓取的時候,會遇到顯示超時了,然后就沒有響應了。這是什么原因的?有的人回答是使用的代理IP質量不行,這種答案,對也不對。 數據抓取時,出現超時的原因時多方面影響的,主要分為目標…

python爬蟲5:requests庫-案例3

python爬蟲5:requests庫-案例3 前言 ? python實現網絡爬蟲非常簡單,只需要掌握一定的基礎知識和一定的庫使用技巧即可。本系列目標旨在梳理相關知識點,方便以后復習。 申明 ? 本系列所涉及的代碼僅用于個人研究與討論,并不會對網…

hivesql-dayofweek 函數

返回日期或時間戳的星期幾。 此函數是 extract(DAYOFWEEK FROM expr) 的同義函數。 語法 dayofweek(expr) 參數 expr:一個 DATE 或 TIMESTAMP 表達式。 返回 一個 INTEGER,其中 1 Sunday 和 7 Saturday。 示例 > SELECT dayofweek(2009-07-30)…

mysql 01.三范式,數據類型

01.概念的區分: mysql是屬于DBMS層次的,sql語句是用于DBMS的語句。 02.sql語句詳細介紹: SQL的概述Structure Query Language(結構化查詢語言)簡稱SQL,它被美國國家標準局(ANSI)確定為關系型數據庫語言的美國標準,后…

神經網絡基礎-神經網絡補充概念-37-其他正則化方法

概念 L1 正則化(Lasso Regularization):L1 正則化通過在損失函數中添加參數的絕對值之和作為懲罰項,促使部分參數變為零,實現特征選擇。適用于稀疏性特征選擇問題。 L2 正則化(Ridge Regularization&…

conda常用命令及國內鏡像源

conda命令使用介紹 啟動conda source ~/.bashrc幫助目錄 conda create -h檢查conda版本 conda --version升級當前版本的conda conda update conda環境管理 列出所有的環境 conda info -e conda env list安裝一個不同版本的python新環境 conda create --name py27 pytho…

PHP FTP的相關函數及簡單使用示例

簡介 FTP是ARPANet的標準文件傳輸協議,該網絡就是現今Internet的前身。 PHP FTP函數是通過文件傳輸協議提供對文件服務器的客戶端訪問,FTP函數用于打開、登陸以及關閉連接,也用于上傳、下載、重命名、刪除以及獲取服務器上文件信息。 安裝 …