全民一起玩Python提高篇第七课:字符串与正则表达式(上)

编码问题

可以通过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()

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值