用python + openpyxl处理excel(07+)文档 + 一些中文处理的技巧

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

寻觅工具

确定任务之后第一步就是找个趁手的库来干活。 Python Excel上列出了xlrd、xlwt、xlutils这几个包,但是

  1. 它们都比较老,xlwt甚至不支持07版以后的excel

  2. 它们的文档不太友好,都可能需要去读源代码,而老姐的任务比较紧,加上我当时在期末,没有这个时间细读源代码

再一番搜索后我找到了openpyxl,支持07+的excel,一直有人在维护,文档清晰易读,参照Tutorial和API文档很快就能上手,就是它了~

安装

这个很容易,直接pip install openpyxl,呵呵呵~

因为我不需要处理图片,就没有装pillow。

一些考虑

  1. 源文件大约一个在1~2MB左右,比较小,所以可以直接读入内存处理。

  2. 既然是处理excel,何况他们整个组显然都是win下干活(数据都用excel存了= =,商科的人啊……),这个脚本还是在win下做吧

  3. 这个任务完全不需要我对现有的文件做修改!囧……我只要读入、处理、再写出另一个文件就行了

学习使用

嗯,就是打开cmd,然后用python的shell各种玩这个模块来上手……(win下没有装ipython,囧)

做这个小脚本基本上我只需要import两个东西

from openpyxl import Workbookfrom openpyxl import load_workbook

load_workbook顾名思义是把文件导入到内存,Workbook是最基本的一个类,用来在内存里创建文件最后写进磁盘的。

干活

首先我需要导入这个文件

inwb = load_workbook(filename)

得到的就是一个workbook对象

然后我需要创建一个新的文件

outwb = Workbook()

接着在这个新文件里,用create_sheet新建几个工作表,比如

careerSheet = outwb.create_sheet(0, 'career')

就会从头部插入一个叫career的工作表(也就是说用法类似python list的insert)

接下来我需要遍历输入文件的每个工作表,并且按照表名做一些工作(e.g.如果表名不是数字,我不需要处理),openpyxl支持用字典一样的方式通过表名获取工作表,获取一个工作簿的表名的方法是get_sheet_names

for sheetName in inwb.get_sheet_names():    if not sheetName.isdigit():        continuesheet = inwb[sheetName]

得到工作表之后,就是按列和行处理了。openpyxl会根据工作表里实际有数据的区域来确定行数和列数,获取行和列的方法是sheet.rows和sheet.columns,它们都可以像list一样用。比如,如果我想跳过数据少于2列的表,可以写

if len(sheet.columns) < 2:    continue

如果我想获取这个工作表的前两列,可以写

colA, colB = sheet.columns[:2]

除了用columns和rows来得到这个工作表的行列之外,还可以用excel的单元格编码来获取一个区域,比如

cells = sheet['A1':'B20']

有点像excel自己的函数,可以拉出一块二维的区域~

为了方便处理,遇到一个没有C列的工作表,我要创建一个和A列等长的空的C列出来,那么我可以用sheet.cell这个方法,通过传入单元格编号和添加空值来创建新列。

alen = len(colA)for i in range(1, alen + 1):sheet.cell('C%s' % (i)).value = None

注意:excel的单元格命名是从1开始的~

上面的代码也显示出来了,获取单元格的值是用cell.value(可以是左值也可以是右值),它的类型可以是字符串、浮点数、整数、或者时间(datetime.datetime),excel文件里也会生成对应类型的数据。

得到每个单元格的值之后,就可以进行操作了~openpyxl会自 动将字符串用unicode编码,所以字符串都是unicode类型的。

除了逐个逐个单元格用cell.value修改值以外,还可以一行行append到工作表里

sheet.append(strA, dateB, numC)

 最后,等新的文件写好,直接用workbook.save保存就行

outwb.save("test.xlsx")

这个会覆盖当前已有的文件,甚至你之前读取到内存的那个文件。

一些要注意的地方

  • 如果要在遍历一列的每个单元格的时候获取当前单元格的在这个column对象里的下标

    for idx, cell in enumerate(colA):    # do something...
  • 为了防止获取的数据两端有看不见的空格(excel文件里很常见的坑),记得strip()

  • 如果工作表里的单元格没有数据,openpyxl会让它的值为None,所以如果要基于单元格的值做处理,不能预先假定它的类型,最好用

    if not cell.value    continue

    之类的语句来先行判断

  • 如果要处理的excel文件里有很多noise,比如当你预期一个单元格是时间的时候,有些表的数据可能是字符串,这时候可以用

    if isinstance(cell.value, unicode):    break

    之类的语句处理。

  • win下的cmd似乎不太好设定用utf-8的code page,如果是简体中文的话可以用936(GBK),print的时候会自动从unicode转换到GBK输出到终端。

 

一些帮忙处理中文问题的小函数

我处理的表有一些超出GBK范围的字符,当我需要把一些信息print出来监控处理进度的时候非常麻烦,好在它们都是可以无视的,我直接用空格替换再print也行,所以加上一些我本来就要替换掉的分隔符,我可以:

复制代码

# annoying seperatorsdot = u'\u00b7'dash = u'\u2014'emph = u'\u2022'dot2 = u'\u2027'seps = (u'.', dot, dash, emph, dot2)def get_clean_ch_string(chstring):    """Remove annoying seperators from the Chinese string.Usage:cleanstring = get_clean_ch_string(chstring)    """cleanstring = chstring    for sep in seps:cleanstring = cleanstring.replace(sep, u' ')    return cleanstring

复制代码

 

此外我还有一个需求,是把英文名[空格]中文名分成英文姓、英文名、中文姓、中文名

首先我需要能把英文和中文分割开,我的办法是用正则匹配,按照常见中英文字符在unicode的范围来套。匹配英文和中文的正则pattern如下:

# regex pattern matching all ascii charactersasciiPattern = ur'[%s]+' % ''.join(chr(i) for i in range(32, 127))# regex pattern matching all common Chinese characters and seporatorschinesePattern = ur'[\u4e00-\u9fff. %s]+' % (''.join(seps))

英文就用ASCII可打印字符的范围替代,常见中文字符的范围是\u4e00-\u9fff,那个seps是前面提到过的超出GBK范围的一些字符。 除了简单的分割,我还需要处理只有中文名没有英文名、只有英文名没有中文名等情况,判断逻辑如下:

复制代码

def split_name(name):    """Split [English name, Chinese name].If one of them is missing, None will be returned instead.Usage:engName, chName = split_name(name)    """matches = re.match('(%s) (%s)' % (asciiPattern, chinesePattern), name)    if matches:  # English name + Chinese namereturn matches.group(1).strip(), matches.group(2).strip()    else:matches = re.findall('(%s)' % (chinesePattern), name)matches = ''.join(matches).strip()        if matches:  # Chinese name onlyreturn None, matches        else:  # English name onlymatches = re.findall('(%s)' % (asciiPattern), name)            return ''.join(matches).strip(), None

复制代码

 

得到了中文名之后,我需要分割成姓和名,因为任务要求不需要把姓名分割得很明确,我就按照常见的中文名姓名分割方式来分——两个字or三个字的第一个字是姓,四个字的前两个字是姓,名字带分隔符的(少数民族名字)分隔符前是姓(这里用到了前面的get_clean_ch_string函数来移除分隔符),名字再长一些又不带分割符的,假设整个字符串都是名字。(注意英语的first name 指的是名,last name指的是姓,2333)

复制代码

def split_ch_name(chName):    """Split the Chinese name into first name and last name.* If the name is XY or XYZ, X will be returned as the last name.* If the name is WXYZ, WX will be returned as the last name.* If the name is ...WXYZ, the whole name will be returnedas the last name.* If the name is ..ABC * XYZ..., the part before the seperatorwill be returned as the last name.Usage:chFirstName, chLastName = split_ch_name(chName)    """if len(chName) < 4:  # XY or XYZchLastName = chName[0]chFirstName = chName[1:]    elif len(chName) == 4:  # WXYZchLastName = chName[:2]chFirstName = chName[2:]    else:  # longercleanName = get_clean_ch_string(chName)nameParts = cleanName.split()        print u' '.join(nameParts)        if len(nameParts) < 2:  # ...WXYZreturn None, nameParts[0]chLastName, chFirstName = nameParts[:2]  # ..ABC * XYZ...return chFirstName, chLastName


转载于:https://my.oschina.net/u/2252538/blog/330467

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/545953.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot 2.3.3 正式发布!

Spring Boot 2.3.3 稳定版已发布&#xff0c;可从 repo.spring.io 和 Maven Central 获取。<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.3.RELEASE</versio…

木板最优切割利润最大_最多进行K笔交易的股票最大买卖利润

木板最优切割利润最大This is a very popular interview problem to find maximum profit in stock buying and selling with at most K transactions. This problem has been featured in the interview rounds of Amazon. 这是一个非常受欢迎的面试问题&#xff0c;目的是在最…

禁止访问磁盘的注册表

百度的了一个禁止访问磁盘的注册表问题怎么禁止访问磁盘&#xff0c;手动操作就会&#xff0c;可是有好几十台啊。手动搞&#xff0c;那个累啊。求个高手&#xff0c;帮我弄个注册表或者BAT文件执行都可以&#xff0c;禁止访问D盘跟E盘。网上找了很多资料&#xff0c;都叫用工具…

C语言文本文件与二进制文件转换

本程序要自己创建个文本格式的输入文件a1.txt&#xff0c;编译后能将文本文件前255字节以内的字符转换成相应的AscII码值的二进制表示&#xff0c;并存入输出文件a2.txt中。然后再将二进制文件还原并存入a3.txt文件。实现文件之间的转换。 具体代码如下&#xff1a; #include …

[数据库]Oracle和mysql中的分页总结

Mysql中的分页物理分页•在sql查询时&#xff0c;从数据库只检索分页需要的数据•通常不同的数据库有着不同的物理分页语句•mysql物理分页&#xff0c;采用limit关键字•例如&#xff1a;检索11-20条 select * from user limit 10,10 ;* 每次只查询10条记录.当点击下一页的时候…

List 集合去重的 3 种方法

问题由来在实际开发的时候&#xff0c;我们经常会碰到这么一个困难&#xff1a;一个集合容器里面有很多重复的对象&#xff0c;里面的对象没有主键&#xff0c;但是根据业务的需求&#xff0c;实际上我们需要根据条件筛选出没有重复的对象。比较暴力的方法&#xff0c;就是根据…

c printf 段错误_错误:预期声明在C中的printf之前指定

c printf 段错误The main cause of this error is - missing opening curly brace ({), before the printf() function. 导致此错误的主要原因是-在printf()函数之前缺少打开的花括号( { )。 Example: 例&#xff1a; #include <stdio.h>int main(void)printf("He…

常用的60招电脑操作

1、如果同时有多个窗口打开&#xff0c;想要关闭的话&#xff0c;可以按住shift不放然后点击窗口右上角的关闭图标。2、在保存网页前&#xff0c;可以按一下"ESC"键(或脱机工作)再保存&#xff0c;这样保存很快 3、用电脑听CD可以不用任何的播放软件&#xff0c;把音…

C语言入门——排序

排序的方法有很多种比较常见的便为&#xff1a;冒泡排序、选择排序、插入排序、快速排序。 今天我们就围绕着四种排序来说&#xff0c;如果有兴趣的话可以去查找一下其他排序。 在排序这方面我们主要讨论&#xff1a; 稳定&#xff1a;如果a原本在b前面&#xff0c;而ab&…

【转】eclipse技巧1

2019独角兽企业重金招聘Python工程师标准>>> 俗话说的好啊&#xff0c;“工于利启事&#xff0c;必先善其器”&#xff0c;如果说你的编程功底是一个枪法的话&#xff0c;那么强大的eclipse就是android战士们最好的武器。 这里&#xff0c;我们来总结eclipse的使用技…

Java LinkedList公共int indexOf(Object o)方法(带示例)

LinkedList公共int indexOf(Object o)方法 (LinkedList public int indexOf(Object o) method) This method is available in package java.util.LinkedList.indexOf(Object o). 软件包java.util.LinkedList.indexOf(Object o)中提供了此方法。 This method is used to return …

定时任务最简单的3种实现方法(超好用)

这是我的第 86 篇原创文章作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;定时任务在实际的开发中特别常见&#xff0c;比如电商平台 30 分钟后自动取消未支付的订单&#x…

C语言入门基础——Brute-Force算法

Brute-Force算法的基本思想是&#xff1a; 1) 从目标串s 的第一个字符起和模式串t的第一个字符进行比较&#xff0c;若相等&#xff0c;则继续逐个比较后续字符&#xff0c;否则从串s 的第二个字符起再重新和串t进行比较。 2) 依此类推&#xff0c;直至串t 中的每个字符依次和…

MFC:2个重载中没有一个可以转换所有参数类型

MFC:2个重载中没有一个可以转换所有参数类型用VS2008&#xff0c;在使用AfxMessageBox函数的时候出现以上错误&#xff0c;代码如下&#xff1a;AfxMessageBox("Here is the information!",MB_ICONINFORMATION);解决办法一&#xff1a;一、 AfxMessageBox(_T("H…

SQL随机生成6位数字

SELECT RIGHT(100000000 CONVERT(bigint, ABS(CHECKSUM(NEWID()))), 6)

为什么劝你放弃Maven?看看Gradle的这些优点就知道了

相信使用Java的同学都用过Maven&#xff0c;这是一个非常经典好用的项目构建工具。但是如果你经常使用Maven&#xff0c;可能会发现Maven有一些地方用的让人不太舒服&#xff1a;Maven的配置文件是XML格式的&#xff0c;假如你的项目依赖的包比较多&#xff0c;那么XML文件就会…

解决问题手册(QT+C++ )

目录前言QTQT介绍QMutexLockerQTimer与事件循环C介绍工作日记介绍2022前言 刚刚参加工作&#xff0c;感觉自己不懂的地方很多。所以我希望做一篇长时间的文章分享&#xff0c;把我工作中遇到的问题还有解决问题的思路都记下来。时间长了它是不是就变成了一本解决问题手册&…

css中的换行符_如何使用CSS防止项目列表中的换行符?

css中的换行符Introduction: 介绍&#xff1a; Dealing with various items in CSS sometimes pose very different problems. The problem could be anything, it could be related to positioning, arrangement, and whatnot, therefore all such kinds of problems require…

Java中的一些坑,汇总篇(2万字)

Photo Drew Farwell 文 | 常意1.前言

VB.NET判断一个路径的文件是否存在

使用文件系统操控文件和路径的能力是任何程序的一个重要功能。在本文所介绍的技巧中&#xff0c;我们将检测VB.NET 如何与文件系统进行作用。通过现有类、方法和属性示例给出简便方法完成必须的功能。为了能够操作文件系统&#xff0c;我们需要用到System.IO命名空间。因此&…