专栏首页Python与Excel之交爱了爱了,扔了网上的正则调试工具后,我吧啦吧啦自己写了一个!(文末附源码以及工具下载)

爱了爱了,扔了网上的正则调试工具后,我吧啦吧啦自己写了一个!(文末附源码以及工具下载)

最近在做个项目,里面经常用到正则表达式,需要不停的调试修改正则表达式,如果直接在程序里跑,是一件很麻烦且缓慢的事,网上有挺多的正则表达式调试网站,奈何这边网络太差,比让人在程序里跑还让人崩溃,所以就自己写了个正则表达式调试小工具。

以下是小工具简单的效果演示:

re库

正则表达式功能强大,用途很广泛,大多数编程语言都可以用,像Python爬虫,对于数据提取阶段,不管网页数据是静态网页还是动态网页,它都可以用,不像Xpath、BeautifulSoup、css、Jsonpath,只能用在特定场景。

在python中,使用正则表达式需要用到re库,所以在制作小工具前,需要先知道re里面有什么方法函数,有什么效果,怎么用。

常用方法

这里讲解几个比较常用的方法,然后挑选合适的方法去打造一个正则表达式调试工具。以下讲解的方法包括:compile、findall、match、fullmatch、search、finditer、sub、subn、split,除了compile方法与其它方法函数的参数pattern的功能重叠,不选用为调试工具的功能,其它的都选用。

findall()

findall方法匹配所有符合匹配规则的内容,返回的是一个列表,pattern为匹配规则(正则表达式), string为要匹配的字符串, flags为修饰符,默认对于0,修饰符包含:S,L,I,M,U,X,A,这里会挑选几个加入调试工具中。

findall(pattern, string, flags)

示例:

text = 'https://mm.enterdesk.com/bizhi/63338.html'
print(re.findall('[a-z]+', text))

结果:

compile()

compile方法为编写一个匹配规则,最终返回的是一个对象。常用于大量构写相同的匹配规则时使用。

compile(pattern, flags)

示例:

text = 'https://mm.enterdesk.com/bizhi/63338.html'
compiles = re.compile('\d+')
print(re.findall(compiles, text))

结果:

match()

match方法是从要匹配的字符串开头开始匹配,匹配到匹配规则不相同的内容时终止,只匹配一次,匹配成功返回一个对象;当开头匹配不符合匹配规则时则返回None。也就是说,字符串的开头不匹配就终止匹配,字符串的开头匹配成功就继续匹配到匹配不成功;参数同上。

match(pattern, string, flags)

示例:

text = 'https://mm.enterdesk.com/bizhi/63338.html'
print(re.match('[\d]+', text))

print(re.match('[a-z]+', text))

结果:

fullmatch()

fullmatch方法与match类似,但fullmatch方法是,匹配的内容从头到尾都要与匹配规则相匹配;参数同上。

fullmatch(pattern, string, flags)

示例:

text = 'https://mm.enterdesk.com/bizhi/63338.html'
print(re.fullmatch('[a-z]+', text))

print(re.fullmatch('[a-z]+://[^\s]+', text))

print(re.fullmatch('[a-z]+://[^\s]+', text).group())

结果:

search()

search方法区别于match,search不要求字符串前面与匹配规则相匹配,直接从字符串中匹配与匹配规则相匹配的第一个内容,也是只匹配一次;参数同上。

search(pattern, string, flags)

示例:

text = 'https://mm.enterdesk.com/bizhi/63338.html'
print(re.search('\d+', text))

print(re.search('\d+', text).group())

结果:

finditer()

finditer区别于findall方法,返回的是一个迭代器,用for循环遍历加group()方法可以打印所匹配的值;参数同上。

finditer(pattern, string, flags)

示例:

text = 'https://mm.enterdesk.com/bizhi/63338.html'
print(re.finditer('([^\s]+)', text))

for i in re.finditer('([^\s]+)', text):
    print(i.group())

结果:

sub()

sub方法是替换掉所匹配的内容,repl是要替换为的字符串,count为最大替换数,默认为0,输入的数值不得小于0。

sub(pattern, repl, string, count, flags)

示例:

text = 'https://mm.enterdesk.com/bizhi/63338.html'
print(re.subn('[a-z]+', '*', text))

结果:

subn()

subnsub类似,但subn返回的是元组, 包含替换完成的新字符串和替换内容的次数。

subn(pattern, repl, string, count, flags)

示例:

text = 'https://mm.enterdesk.com/bizhi/63338.html'
print(re.subn('[\d]+', '*', text))

结果:

split()

split为切割匹配,根据匹配规则,把匹配规则以及匹配规则左右的 内容进行切割,最终形成一个list,maxsplit为最大匹配数,默认为0,不得小于0。

split(pattern, string, maxsplit, flags)

示例:

text = 'https://mm.enterdesk.com/bizhi/63338.html'
print(re.split('/', text, maxsplit=0))

print(re.split('/', text, maxsplit=2))

结果:

编写工具

可视化界面是用PySimpleGUI库来进行编写,用re来编写正则表达式底层逻辑。本文只要到这两个库,安装用pip命令即可!

设计逻辑

对于最终的成果,应该是与直接在程序里写正则表达式差不多的,那么,该工具要实现正则表达式的调试,就要从正常写正则表达式的步骤设计。

这里拿findall方法进行举例说明:

findall(pattern, string, flags)

上面有说到findall含有三个参数,分别为:

  • pattern - 正则表达式
  • string- 要匹配的字符串
  • flags - 修饰符

按照findall方法的用法,我们必须要输入 patternstring参数,而flags默认等于0,可选可不选。从用法上看,我们必须要从界面中获取 patternstring参数,而flags可以进行选择性传入,那么我们的GUI界面必须存在传入这三个参数的输入框或者选择框!

  • pattern- 正则表达式输入框
  • string- 要匹配的字符串输入框
  • flags- 修饰符输入、选择框

flags因为不只有一个,含有:S,L,I,M,U,X,A,所以我们需要创建一个输入、选择下拉文本框框,方便我们选择,并且在程序上设置它默认为0!

另外,工具中的正则匹配方法有八个,且有几个方法的参数是不同的,所以我们要区分开来,创建不同的传参人口。比如subn方法,它除了pattern, string, flags参数, 还会有count,repl参数:

subn(pattern, repl, string, count, flags)

而八个方法函数我们也要在匹配内容时声明一下,也就是创建一个输入、选择下拉文本框,方便我们选择正确的方法。

基于上面的逻辑,我创建了对应八个方法的函数,设置了传参变量。后面需要使用相应的方法时,可以直接调用函数:

def re_findall(patterns, strings, flags):
    findall = re.findall(patterns, strings, flags)
    print(findall)

def re_match(patterns, strings, flags):
    match = re.match(patterns, strings, flags)
    print(match)

def re_fullmatch(patterns, strings, flags):
    fullmatch = re.fullmatch(patterns, strings, flags)
    print(fullmatch)

def re_search(patterns, strings, flags):
    search = re.search(patterns, strings, flags)
    print(search)

def re_finditer(patterns, strings, flags):
    finditer = re.finditer(patterns, strings, flags)
    print(finditer)

def re_sub(patterns, repl, strings, count, flags):
    sub = re.sub(patterns, repl, strings, count, flags)
    print(sub)

def re_subn(patterns, repl, strings, count, flags):
    subn = re.subn(patterns, repl, strings, count, flags)
    print(subn)

def re_split(patterns, strings, maxsplit, flags):
    split = re.split(patterns, strings, maxsplit, flags)
    print(split)

通过调用函数,可以直接打印出匹配结果,并通过界面输出文本框进行展示。

GUI界面设计

通过上面简单的逻辑讲解,我们知道可视化界面中需要的几个元素:

  • 正则表达式输入文本框 - InputText
  • 方法函数输入、选择下拉文本框 - Combo
  • 修饰符输入、选择下拉文本框 - Combo
  • 要匹配的内容输入文本框(多行)- Multiline
  • 开始匹配按钮 - Button
  • 结果输出文本框 - Output

基于上面的内容,我设计出以下GUI界面:

除了基本的元素,我另外还在界面中添加了清空匹配内容清空匹配结果按钮。

基于上面的GUI界面设计,我们得出以下代码::

sg.theme('LightBrown3')
# 方法名称
method = ['findall', 'match', 'fullmatch', 'search', 'finditer', 'sub', 'subn', 'split']
# 修饰符
mode = ['S', 'I', 'M', 'U', 'X']
# 布局设置
layout = [[
    sg.Column([
        [sg.Text('正则表达式:', font=("微软雅黑", 12)),
         # InputText输入文本框,正则表达式输入文本框
         sg.InputText(key='keys', size=(49, 1), font=("微软雅黑", 10), enable_events=True),
         # Button按钮
         sg.Button('开始匹配', font=("微软雅黑", 12))
         ],

        [sg.Text('请选择或输入方法名:', font=("微软雅黑", 12)),
          # Combo下拉框
         sg.Combo(values=method, tooltip='选择或输入方法', font=("微软雅黑", 10), auto_size_text=True,
                  size=(14, 10), key='method'),

         sg.Text('请选择或输入修饰符:', font=("微软雅黑", 12)),
         sg.Combo(values=mode, tooltip='选择或输入修饰符', font=("微软雅黑", 10), auto_size_text=True,
                  size=(13, 10), key='mode')],

        [sg.Text('-' * 37 + '匹配内容' + '-' * 37, justification='center', text_color='blue')],
        # Multiline多行文本框
        [sg.Multiline(key='content', s=(70, 20), font=("微软雅黑", 10), text_color='red')],

        [sg.Button('清空匹配内容', font=("微软雅黑", 12))]

    ]),
    # 给两个布局加一条线
    sg.VSeperator(),
    sg.Column([
        [sg.Text('-' * 37 + '匹配结果' + '-' * 37, justification='center', text_color='blue')],
        [sg.Output(key='result', size=(70, 24), font=("微软雅黑", 10), text_color='red')],

        [sg.Text('', font=("微软雅黑", 12), size=(46, 0)), sg.Button('清空匹配结果', font=("微软雅黑", 12))]
    ])
]]
# 创建窗口
window = sg.Window('正则表达式调试器', layout, font=("微软雅黑", 12), default_element_size=(80, 1))

while True:
    # 退出按钮
    event, values = window.read()
    if event in (None, 'Exit'):
        break
        
window.close()

用户交互逻辑

对于参数内容的接收和匹配结果的输出,我刚开始是使用exec函数,因为他简洁,且不繁琐,只需要一句话即可:

exec(r'print(re.{}("{}", "{}", {}))'.format(method, patterns, strings, flags))

但这句话在实际操作中错误有很多,因为他常常在接收参数时发生错误,所以我选择了一种繁琐,但稳定的方式:

if event == '开始匹配':  
  # 之所以使用strip(),是因为多行文本框具有多余的换行符
     if values['keys'] and values['content'].strip():
         a = values['keys']    # 正则表达式
         b = values['content'].strip()  
         if values['method'] == 'findall':  # 判断方法,再选择修饰符,不选择时默认为0 
             if values['mode'] == 'S':
                 re_findall(patterns=str(a), strings=str(b), flags=re.S)
             elif values['mode'] == 'I':
                 re_findall(patterns=str(a), strings=str(b), flags=re.I)
             elif values['mode'] == 'M':
                 re_findall(patterns=str(a), strings=str(b), flags=re.M)
             elif values['mode'] == 'U':
                 re_findall(patterns=str(a), strings=str(b), flags=re.U)
             elif values['mode'] == 'X':
                 re_findall(patterns=str(a), strings=str(b), flags=re.X)
             else:
                 re_findall(patterns=str(a), strings=str(b), flags=0)

与findall方法相同,match、fullmatch、search、finditer方法都是使用以上逻辑进行调用。其实是可以把一些修饰符删除的,但为了工具变得完美一些,我就不删除了。

其它三个方法中因为参数不相同,在调用这三个方法时,用popup_get_text方法创建弹窗输入框,从而获取不相同的参数:

sub_count为最大替换数,是数值类型,而从popup_get_text方法创建的弹窗输入框得到的是字符串,所以要进行转换成数值类型:

elif values['method'] == 'sub':
    sub_repl = sg.popup_get_text('请输入要替换的字符:', title='repl')
     if sub_repl:
         sub_count = sg.popup_get_text('请输入最大替换数:', title='count')
         if sub_count and int(sub_count) >= 0:  # 在输入框中输入的是字符串,要进行转换
             if values['mode'] == 'S':
                 re_sub(patterns=str(a), repl=sub_repl, strings=str(b), count=int(sub_count), flags=re.S)
             elif values['mode'] == 'I':
                 re_sub(patterns=str(a), repl=sub_repl, strings=str(b), count=int(sub_count), flags=re.I)
             elif values['mode'] == 'M':
                 re_sub(patterns=str(a), repl=sub_repl, strings=str(b), count=int(sub_count), flags=re.M)
             elif values['mode'] == 'U':
                 re_sub(patterns=str(a), repl=sub_repl, strings=str(b), count=int(sub_count), flags=re.U)
             elif values['mode'] == 'X':
                 re_sub(patterns=str(a), repl=sub_repl, strings=str(b), count=int(sub_count), flags=re.X)
             else:
                 re_sub(patterns=str(a), repl=sub_repl, strings=str(b), count=int(sub_count), flags=0)
         else:
             sg.popup('count未输入或者输入的数值小于0!')
     else:
         sg.popup('repl未输入!')

其它几个方法函数的调用逻辑差不多,这里就不再展示了。

清空内容按钮,用的是Update方法,FindElement获取的匹配内容多行文本框和匹配结果输出文本框的key值:

if event == "清空匹配内容":
    window.FindElement("content").Update("")
elif event == "清空匹配结果":
    window.FindElement("result").Update("")

打包

打包可以通过pyinstaller库,安装只需要pip命令即可!安装后在命令行窗口cd到文件所在的文件目录中,最后用下面命令进行打包:

pyinstaller -F -w 名称.py

打包过程没出现什么状况,会得到几个文件,进入dist文件夹,就可以看见.exe文件了:

结语

虽然小工具做出来了,但我感觉不够Pythonic,总体上不是很满意,下面我还会尝试进行优化设计的。

完整的源码以及小工具已在公众号存着,感兴趣的小伙伴可以关注“Python与Excel之交”公众号,后台回复"正则"获取本文完整代码!

以上便是今天的全部内容了,如果你喜欢今天的内容,希望你能在下方点个赞和在看支持我,谢谢!

本文分享自微信公众号 - Python与Excel之交(Yi-Python-Excel),作者:锋小刀

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-08-30

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 在VR环境中养一只专属宠物,是种什么样的体验?

    没有时间和精力养宠物?但看见软糯糯的小家伙们又移不开脚步,这说的就是当代打工人吧。

    VRPinea
  • 记录一次简单的博客升级w

    从过年开始一直被闷在家里,少了出门和小伙伴耍的快落~每天在家里就是对着电脑忙各种事情(指摸鱼),于是总想着找点事情做做,正好看自己的小博客也不太顺眼了就想着升一...

    idealclover
  • Google Chrome谷歌/火狐/Safari浏览器开发者工具基本使用教程

    在阅读下面内容之前,那么些简单的了解浏览器开发者工具到底是什么东西,到底有什么用途。

    yaohong
  • 一名黑客在网吧能做出什么神操作?

    链接:https://www.zhihu.com/question/343894667/answer/866283587

    Bypass
  • 软妹音程序员鼓励师24小时在线,只需一个VSCode插件,还能帮忙吐槽产品经理

    旁边工位的小李扭头看了他一眼:“大哥,你在听啥不可描述的东西呢?”顺势拔掉了小王的耳机线。

    量子位
  • 最全的微信QQ特效昵称都在这啦!帮你打包好了

    复制完成之后,打开【微信】-【我】-【名字】,将括号复制粘贴进去,将括号删除,点击保存就OK了。

    IT小侠公社
  • 用Python抢枪过年的火车票

    前言:大家跟我一起念,Python***好,跟着本宝宝用Python抢火车票 首先我们需要splinter 安装: pip install splinter -...

    小莹莹
  • CocosCreator + socketIO简易教程(更新至1.0)

    我们从已经安装了CocosCreator 懂得建立HelloWorld项目 有前台与后台交互基本思想 但是完全不知道node.js是啥 的前提开始讲 提醒...

    bering
  • 【python系统学习05】input函数——实现人机交互

    你提出的问题就是小括号“()”里边的那段字符串。result接受的就是运行的人输入的回答。运行的人按下回车,流程向下继续走。

    xing.org1^
  • 仿真那些事儿

    说到“仿真”这个词,我相信,只要是搞通信的朋友,一定都不会陌生。不仅在很多通信职位的实际工作中经常会用到,在学校里,也有专门的课程。

    鲜枣课堂
  • 爱情36技之一劳永逸

    今天雅兴又起,再续爱情36技。大概率你们已经淡忘了 Java 那小子与 Python 菇凉浪漫的爱情故事,容我再帮着给大家回味一下。

    一猿小讲
  • 出不了门的日子,我选择在 GitHub 上快乐的打游戏

    2020 年的开年因为一些大家都知道的原因,有些不顺,但还是要捏捏自己的脸蛋儿,微笑的面对,毕竟日子还是要过下去...

    编程文青李狗蛋
  • 出不了门的日子,自闭的我选择在 GitHub 上快乐的打游戏

    2020 年的开年因为一些大家都知道的原因,有些不顺,但还是要捏捏自己的脸蛋儿,微笑的面对,毕竟日子还是要过下去...

    帅地
  • 做一名程序员需要学哪些知识?

    问这个问题的人都该打,先拖出去,赏一丈红~ 如果你是计算机学生或者意欲从事IT行业的人,那么再仗50大板!! 为什么?因为你肯定想都没有想过这个问题,一个典型的...

    用户1667431
  • 跟大神一起十五分钟制作一个属于自己得Linux操作系统!

    一、前言 Linux操作系统至1991年10月5日诞生以来,就其开源性和自由性得到了很多技术大牛的青睐,每个Linux爱好者都为其贡献了自己的一份力,不管是在L...

    小小科
  • 跟大神一起十五分钟制作一个属于自己得Linux操作系统!

    Linux操作系统至1991年10月5日诞生以来,就其开源性和自由性得到了很多技术大牛的青睐,每个Linux爱好者都为其贡献了自己的一份力,不管是在Linux内...

    马哥linux运维
  • ARM 交叉编译环境搭建

    最近研究了一下ARM的交叉编译环境搭建,太麻烦了必须作一下记录啊。 前两个方法比较简单一点,关键是淫家Google帮你弄好了大部分功能

    owent
  • 懒人制作学术会议 Oral/Spotlight Video指南

    在疫情影响下,不少学术会议都变成了线上举行,于是乎制作在线上会议上使用的oral视频成了科研工作者们的新任务,最近做了BBN工作CVPR2020 oral材料,...

    AI科技评论
  • 有了这款神器,人人都是作曲家!

    摘要:人工智能作曲APP Amper Music的简单介绍和测评,以及人工智能和机器学习的小科普

    生信宝典

扫码关注云+社区

领取腾讯云代金券