编码问题
可以通过chardet来读取文件编码方式
import chardet
for i in range(4):
try:
with open(f'E:/拷贝过来的文件/全民一起玩Python/MyProject/Test1/提高篇第二十课/python_02_21_01/file{i}.txt','rb') as f:
b = f.read()
d=chardet.detect(b)
print(d)
s=[]
with open(f'E:/拷贝过来的文件/全民一起玩Python/MyProject/Test1/提高篇第二十课/python_02_21_01/file{i}.txt', encoding=d['encoding'])as f:
#找到编码方案
s=f.readlines()
print(s)
except Exception as e:
print('出现未知错误 ')
{'encoding': 'GB2312', 'confidence': 0.99, 'language': 'Chinese'}
['操曰:“使君知龙之变化否?”\n', '玄德曰:“未知其详。”\n', '操曰:“龙能大能小,能升能隐;大则兴云吐雾,小则隐介藏形;升则飞腾于宇宙之间,隐则潜伏于波涛之内。方今春深,龙乘时变化,犹人得志而纵横四海。龙之为物,可比世之英雄。玄德久历四方,必知当世英雄。请试指言之。” ']
{'encoding': 'utf-8', 'confidence': 0.99, 'language': ''}
['操曰:“使君知龙之变化否?”\n', '玄德曰:“未知其详。”\n', '操曰:“龙能大能小,能升能隐;大则兴云吐雾,小则隐介藏形;升则飞腾于宇宙之间,隐则潜伏于波涛之内。方今春深,龙乘时变化,犹人得志而纵横四海。龙之为物,可比世之英雄。玄德久历四方,必知当世英雄。请试指言之。” ']
{'encoding': 'UTF-16', 'confidence': 1.0, 'language': ''}
['操曰:“使君知龙之变化否?”\n', '玄德曰:“未知其详。”\n', '操曰:“龙能大能小,能升能隐;大则兴云吐雾,小则隐介藏形;升则飞腾于宇宙之间,隐则潜伏于波涛之内。方今春深,龙乘时变化,犹人得志而纵横四海。龙之为物,可比世之英雄。玄德久历四方,必知当世英雄。请试指言之。” ']
{'encoding': 'UTF-32', 'confidence': 1.0, 'language': ''}
['操曰:“使君知龙之变化否?”\n', '玄德曰:“未知其详。”\n', '操曰:“龙能大能小,能升能隐;大则兴云吐雾,小则隐介藏形;升则飞腾于宇宙之间,隐则潜伏于波涛之内。方今春深,龙乘时变化,犹人得志而纵横四海。龙之为物,可比世之英雄。玄德久历四方,必知当世英雄。请试指言之。” ']
凯撒密码
以偏移量等于 3 为例,其完整替换规则如下:
明文字母表:ABCDEFGHIJKLMNOPQRSTUVWXYZ
密文字母表:DEFGHIJKLMNOPQRSTUVWXYZABC
s=input('请输入要加密的符文')
num=int(input('请输入加密偏移量'))
result=''
for i in s:
i=chr(ord(i)+num)
result=result+i
print(result)
生成编码
请编写一个python程序,运行后要求用户输入三个信息:源文件路径名称、新文件路径名称、目标编码名称,就可以读取源文件、然后按照指定的目标编码进行编码转换,最后按照新文件名保存为新的文件。
import chardet
sourcepath=input('源路径')
newpath=input('新路径')
name=input('目标编码名称:')
f1 = open(sourcepath, 'rb')
s1 = f1.read()
e=chardet.detect(s1)['encoding']
if e.lower().startswith('gb'):
#统一用国标的
e='gb18030'
s2=s1.decode(e)
#解码
f3 = open(newpath, 'wb')
f3.write(s2.encode(name))
如果想让 chardet 判断出某段文本数据的编码名称,必须将该文本的原始二进制形式(即字节流)交给chardet的detect 方法,以便其观察数值特征和统计分析。
所以打开方式要用’rb’
此时不能再使用 f.readline() 方法读取文件内容,而应使用 b=f.read() 或 f.write(b) 方法。
对于任何来源的文本数据(文本文件、网络网页、数据库 ……),如果发现乱码,都可以用下面的思路解决:
使用字节流方式读取该来源,比如 open(文件名,‘rb’) ,将原始字节数据存入一个bytes对象;
将该 bytes 对象交给 chardet 等工具,获取最可能的编码名称;
调用该 bytes 对象的 decode 方法,按照获取的编码名称将其转换为字符串显示。.
正则表达式
在学VBA的时候已经学习了正则表达式的基本语法,这里主要着重于回顾,加强记忆。
全民一起VBA提高篇第九课:正则表达式入门
在Python中引入正则表达式
import re
#引入 Regular Expression
s='010-0034201'
a=re.findall('\d+',s)
#找到所有的数字,返回的是一个列表
print(a)
题目
编写Python程序,将其中所有电话号码都提取出来,并保存到新的文本文件中。
import re
with open('E:\拷贝过来的文件\全民一起玩Python\MyProject\Test1\提高篇第二十三课\python02_23_01.txt','r',encoding='utf-8') as f:
s=f.read()
a=re.findall('\d+-\d+',s)
print(a)
with open('d:/电话号码.txt', 'w', encoding='utf-8') as f:
f.write('\n'.join(a) )
#连成字符串才能输出到文件
用VBA写类似功能
Option Explicit
Sub 读写文件()
Call 读取
Call 处理文本
Call 写入
End Sub
Sub 读取()
Dim s As String, i As Long
Open "E:\拷贝过来的文件\全民一起玩Python\MyProject\Test1\提高篇第二十三课\python02_23.txt" For Input As #1
'给每个打开的文件一个数字编号
'打开一个文件
i = 1
Do While Not EOF(1)
'判断文本是否读完
Line Input #1, s
Cells(i, 1) = s
i = i + 1
Loop
Close #1
'关闭保存
End Sub
Sub 处理文本()
Dim i As Long, s As String, myreg As Object
Dim mymatches As Object, mymatch As Object
Dim j As Long
j = 1
Set myreg = CreateObject("vbscript.regexp")
'引入正则表达式功能
myreg.Global = True
'引入正则表达式代码
myreg.Pattern = "(\d+)-(\d+)"
'若干数字-若干数字
For i = 1 To 84
s = Range("A" & j).Value
Set mymatches = myreg.Execute(s)
For Each mymatch In mymatches
'循环扫描两捕获组
Cells(j, 2) = mymatch.submatches(0)
Cells(j, 3) = mymatch.submatches(1)
j = j + 1
Next mymatch
Next i
End Sub
Sub 写入()
Dim s As String, i As Long
Dim w As Worksheet
Open "E:\拷贝过来的文件\全民一起玩Python\MyProject\Test1\提高篇第二十三课\客户信息.txt" For Output As #1
For Each w In Worksheets
i = 2
Do While Trim(w.Cells(i, 1)) <> ""
Print #1, w.Cells(i, 2); "-"; w.Cells(i, 3)
i = i + 1
Loop
Next w
Close #1
'每一行print结束没有分号,默认换行,给个分号,接着一行
End Sub
反义词匹配
使用方括号将多个字符括在一起,即是一个“字符组”。在匹配过程中,整个字符组匹配一个字符,且该字符必须是方括号内的某一个字符。比如[0123456789] 代表任意一个数字字符,或者写[0-9],相当于 \d
案例:
A公司,发货5000台,联系人:张三,电话018-88223343,邮箱zs@a.com
B公司:联系人:李四,电话:0418-5566778,邮箱:1isigb.com
C公司发货200台,联系人:王五,电话是(024)66667777,邮箱:wangwugc.com。
D公司电话联系,联系人:赵六,电话0520-33227788,邮箱是zhaoliued.com.
E公司联系人:田七,电话01083232563,邮箱tianqige.com
F公司,联系人:John Willams,电话(01)33243334,邮箱johnwef.com
G公司,联系人:Ken Wang,电话(881)56523333,邮箱kenwangeg.com
使用[a n]来匹配,
只匹配 a或者n,连在一起的an也是算2个字符
找字母,可以写为[a-z A-Z],等价于\
找所有标点
减号当做减号用,那就要放开头或结尾,否则会被认为是连字符
点号认为是普通点号,加号问号这种只代表自己了,和位置也无关
设计正则表达式的一般流程:
- 找到目标文本的样本,肉眼观察期通用格式;
- 将其中可变部分(比如任意数字、任意字母等)用元字符代替;
- 对连续出现的内容使用量词进行描述;
- 在测试工具中检验结果、不断修正(根据需要找出更多目标文本的独有特征);
- 将最终的正则表达式写到 Python 程序中,即 re.findall() 等方法里。
以上面的示例为例:
若干数字 花括号或者是减号 若干数字
\d+[-\s()]\d+
但张三的没有匹配出来,因为减号附近有多个空格
满足多个空格,添加加号
\d+[-\s()]+\d+
但是田七还是没匹配到,他是连续数字,也就是说允许出现0次1次和多次
把加号改为**号
\d+[-\s()]*\d+
但把前面的数字也匹配了,所以我们要继续挖掘数字特征
每个电话号码前面都是电话,跟的是空格,括号,是,冒号等条件
所以修改为
电话[是\s:(]星\d+[-\s()]星\d+
^表示非,但一定要写开头,不然就当普通的了
我们再找一下所有的联系人
观察一下格式
以 联系人:开头 以逗号结尾
如果直接用点号,就会进行贪婪搜索,得不到理想的情况两者之间的内容,可以是所有的非逗号
所以写为
联系人:[^, ]+,
为简化书写,正则表达式中定义了一些常用的反义元字符,它们都是大写字母形式。比如 \D 代表所有非数字字符(即 \d 的反义)、\S 代表所有非空白字符(即 \s 反义)、\W 代表所有非文字字符(即 \w 反义)
题目:处理材料清单
请先下载 Excel 工作簿 型材用料清单 ,然后在 作业1 的基础上修改程序,使之将该工作簿中所有以字母 a 到 e 开头的型号(即所谓“关键用料”),全部打印到屏幕上。
完成此任务后,请进一步修改程序,扫描工作簿每行数据,找出每行C列数据中的“关键用料”(即字母 a 到 e 开头的型号),依次填写在该行的 D 到 G 列中 (找到几项就填写几列、没找到则不填写)。
import re
import xlwings as xw
app=xw.App()
wb=app.books.open('E:\拷贝过来的文件\全民一起玩Python\MyProject\Test1\提高篇第二十五课\提高篇第25课.xlsx')
用料型号=wb.sheets['Sheet1'].range('C3:C302').value
E = [''.join(sub_list) for sub_list in 用料型号]
#多维列表变为一维列表
用料型号=list(''.join(E))
#一维列表变字符串
#把字符串拆为各个单字组成的列表
print(E)
j=3
for i in E:
a=re.findall('[a-z]\d+',i)
wb.sheets['Sheet1'].range('D'+ str(j)).value=a[0]
wb.sheets['Sheet1'].range('E' + str(j)).value = str(a[1])
wb.sheets['Sheet1'].range('F' + str(j)).value = str(a[2])
wb.sheets['Sheet1'].range('G' + str(j)).value = str(a[3])
print(a[0],a[1],a[2],a[3])
j=j+1
wb.save()
wb.close()
app.quit()