前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >爱了爱了,扔了网上的正则调试工具后,我吧啦吧啦自己写了一个!(文末附源码以及工具下载)

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

作者头像
Python与Excel之交
发布2021-09-06 16:07:26
4920
发布2021-09-06 16:07:26
举报
文章被收录于专栏: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,这里会挑选几个加入调试工具中。

代码语言:javascript
复制
findall(pattern, string, flags)

示例:

代码语言:javascript
复制
text = 'https://mm.enterdesk.com/bizhi/63338.html'
print(re.findall('[a-z]+', text))

结果:

compile()

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

代码语言:javascript
复制
compile(pattern, flags)

示例:

代码语言:javascript
复制
text = 'https://mm.enterdesk.com/bizhi/63338.html'
compiles = re.compile('\d+')
print(re.findall(compiles, text))

结果:

match()

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

代码语言:javascript
复制
match(pattern, string, flags)

示例:

代码语言:javascript
复制
text = 'https://mm.enterdesk.com/bizhi/63338.html'
print(re.match('[\d]+', text))

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

结果:

fullmatch()

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

代码语言:javascript
复制
fullmatch(pattern, string, flags)

示例:

代码语言:javascript
复制
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不要求字符串前面与匹配规则相匹配,直接从字符串中匹配与匹配规则相匹配的第一个内容,也是只匹配一次;参数同上。

代码语言:javascript
复制
search(pattern, string, flags)

示例:

代码语言:javascript
复制
text = 'https://mm.enterdesk.com/bizhi/63338.html'
print(re.search('\d+', text))

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

结果:

finditer()

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

代码语言:javascript
复制
finditer(pattern, string, flags)

示例:

代码语言:javascript
复制
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。

代码语言:javascript
复制
sub(pattern, repl, string, count, flags)

示例:

代码语言:javascript
复制
text = 'https://mm.enterdesk.com/bizhi/63338.html'
print(re.subn('[a-z]+', '*', text))

结果:

subn()

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

代码语言:javascript
复制
subn(pattern, repl, string, count, flags)

示例:

代码语言:javascript
复制
text = 'https://mm.enterdesk.com/bizhi/63338.html'
print(re.subn('[\d]+', '*', text))

结果:

split()

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

代码语言:javascript
复制
split(pattern, string, maxsplit, flags)

示例:

代码语言:javascript
复制
text = 'https://mm.enterdesk.com/bizhi/63338.html'
print(re.split('/', text, maxsplit=0))

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

结果:

编写工具

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

设计逻辑

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

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

代码语言:javascript
复制
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参数:

代码语言:javascript
复制
subn(pattern, repl, string, count, flags)

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

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

代码语言:javascript
复制
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界面设计,我们得出以下代码::

代码语言:javascript
复制
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函数,因为他简洁,且不繁琐,只需要一句话即可:

代码语言:javascript
复制
exec(r'print(re.{}("{}", "{}", {}))'.format(method, patterns, strings, flags))

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

代码语言:javascript
复制
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方法创建的弹窗输入框得到的是字符串,所以要进行转换成数值类型:

代码语言:javascript
复制
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值:

代码语言:javascript
复制
if event == "清空匹配内容":
    window.FindElement("content").Update("")
elif event == "清空匹配结果":
    window.FindElement("result").Update("")

打包

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

代码语言:javascript
复制
pyinstaller -F -w 名称.py

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

结语

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

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

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-08-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python与Excel之交 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • re库
  • 常用方法
    • findall()
      • compile()
        • match()
          • fullmatch()
            • search()
              • finditer()
                • sub()
                  • subn()
                    • split()
                    • 编写工具
                      • 设计逻辑
                        • GUI界面设计
                          • 用户交互逻辑
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档