如何才能写出一个符合预期的正则?

news2024/10/7 8:23:54

如何才能写出一个符合预期的正则?

  • 正则表达式入门
  • 示例讲解
    • 1、java里正则表达式replaceAll
      • 连续的字符
      • 正则测试
      • 题主问题讲解
    • 2、开发者遇到金额的校验
      • 正则描述
      • 正则测试
    • 3、java正则表达式匹配字符串
      • 正则描述
      • 正则测试
    • 4、关于#正则表达式#的问题,如何解决?
      • 正则描述
      • 正则测试
      • 进阶实现
  • 小结

正则表达式入门

随着爬虫日益普及,很多人开始捡起了正则,做一些简单的信息提取处理,越来越多的个性化正则表达式的需求,可还是有很多人不知道怎么下手,无法编写出一个强壮的正则,毕竟看起来和乱码差不多。

老顾这里用几个问答小伙伴的例子,来简单说一下,正则的写法。

不过,本文不讲述正则的基本支持,有需要补课的小伙伴,可以看老顾以前的文章:

《文盲的正则表达式入门》
《揭开正则表达式的神秘面纱》
《python 正则使用详解》
《文盲的正则表达式入门,实战篇》

老顾之前发了个实战篇,本意是有小伙伴可以提问,结果老顾高估了自己的人气,所以一直也没有小伙伴提问,所以老顾干脆,从新从另外一个角度,来讲述一下怎么写正则表达式好了。希望大家看完本文,能够自己写出强壮的正则来。

示例讲解

1、java里正则表达式replaceAll

问答地址:https://ask.csdn.net/questions/7919433?spm=1005.2025.3001.5141

预期结果是abcd,为什么运行结果是ad啊

        String s = "abbbbccccdddddddddd";
        String s1 = s.replaceAll("((.)\\2)+", "$2");

问题描述:有字符串“abbbbccccdddddddddd”,期望所有连续重复的字符只保留一个

一个简单的问题,我们只需要把问题描述改成正则描述即可

连续的字符

判断连续的字符,需要用到分组,即将任意字符作为一个分组,然后后边跟随该分组引用

(.)(?:\1)*

这个正则片段中,第一个括号表示分组,第二个括号,老顾加上了?: 修饰,表示不参与分组,\1 表示引用第一个分组,然后对引用分组的结果加上一个长度修饰,老顾用的是*,表示0到多个,然后,因为默认长度模式是贪婪模式,所以,这个正则就算完成了,然后,在替换部分也加上引用就可以了。

正则测试

python 测试

import re
print(re.sub(r'(.)(?:\1)*','\\1','abbbbccccdddddddddd'))
abcd
print(re.sub(r'(.)(?:\1)*','\\1','aabaacadaadde'))
abacadade

javascript 测试

'abbbbccccdddddddddd'.replace(/(.)(?:\1)*/gi,'$1')
'abcd'
'aabaacadaadde'.replace(/(.)(?:\1)*/gi,'$1')
'abacadade'

题主问题讲解

题主在问答中,给出了自己的正则

((.)\2)+

这里需要注意模式问题哦,这个正则解读如下

字符串数据:abbbbccccdddddddddd
正则表达式:((.)\2)+  

首先是 (.) 表示任意字符,并放入分组
然后是(.)\2 ,因为外层还有一个分组,所以内层分组的分组序号是2,这里表示引用前边的这个(.) 的匹配结果,也就是连续字符,比如 bb,比如 cc
再然后是对连续字符的分组 ((.)\2)+ 并有长度修饰,注意,长度修饰是贪婪模式哦,所以这个正则匹配到的内容是
bbbbccccdddddddddd,所以在使用替换的时候,这么一大串,会当做一个匹配来处理
最后替换引用的 $2,也就是第二个分组内容,是在上述匹配时,最后一个符合的内容
bb bb cc cc dd dd dd dd dd,那么最后一个符合分组的匹配是 dd,所以第二个引用的结果就是字母 d
所以破案了,题主的结果为什么是 ad

2、开发者遇到金额的校验

问答地址:https://ask.csdn.net/questions/7916098?spm=1005.2025.3001.5141

一个金额的正则校验,整数部分最多16位,以千分位展示,小数点后保留两位小数且第三位不可输入

看题主的意思,应该是一个数据验证,校验输入的数据是否符合金额的千分格式

正则描述

这个正则稍微复杂了一点,他的需求可以拆分为几个小的描述

1、整数部分最多16位
2、整数部分以千分位展示
3、小数点后保留两位小数

那么,逻辑就出来了,小数点后保留两位是必须得,整数部分长度是最大16位,然后每三位加一个逗号的样子,也就是21位

所以第一个片段,我们先验证字符串长度

^(?=[^\.]{1,21}(?=\.))

这个片段是什么意思呢?
^ 表示从字符串开头开始匹配
(?=) 表示右断言,或者说预搜索,表示从当前位置,后边的内容应该是这个样子的
[^\.]{1,21} 表示除了小数点之外,其他任意字符,长度在1到21之间
(?=\.) 后边又跟了一个右断言,表示上述长度的字符串后,必须跟一个小数点的样子

那么小数点之前的长度验证完成了,然后我们需要验证是否是千分位格式,这个时候就不用断言了

\d{1,3}(,\d{3})*\.\d{2}$

这个片段的意思就是
\d{1,3} 必须是1到3个数字开头
(,\d{3})* 后边跟上多个以逗号开头的三位数
\. 然后是必须有的小数点
\d{2} 然后是一个必须有的小数点后两位数
$ 最后是字符串结束

那么完整的正则就是

^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$

正则测试

python 测试

print(re.search(r'^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$','100'))
None
print(re.search(r'^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$','100.00'))
<re.Match object; span=(0, 6), match='100.00'>
print(re.search(r'^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$','100.000'))
None
print(re.search(r'^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$','1000.00'))
None
print(re.search(r'^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$','1,000.00'))
<re.Match object; span=(0, 8), match='1,000.00'>
print(re.search(r'^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$','10,000,000,000,000,000.00'))
None
print(re.search(r'^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$','1,000,000,000,000,000.00'))
<re.Match object; span=(0, 24), match='1,000,000,000,000,000.00'>

javascript 测试

/^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$/gi.test('100')
false
/^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$/gi.test('100.00')
true
/^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$/gi.test('100.000')
false
/^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$/gi.test('1000.000')
false
/^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$/gi.test('1,000.00')
true
/^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$/gi.test('1,000,000,000,000,000.00')
true
/^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$/gi.test('10,000,000,000,000,000.00')
false

3、java正则表达式匹配字符串

问答地址:https://ask.csdn.net/questions/7916062?spm=1005.2025.3001.5141

#java正则 #正则表达式分割#java断言

请教,想要根据 ( ) 外的 | 分割字符串,正则表达是该如何匹配呢?

例如:

%这个一个测试2|4\)11|(0jh|96)78|8\)k|字符串%   分割后应为 如果是 \(  \)  则不不认为是括号

%这个一个测试2
4\)11
(0jh|96)78
8\)k
字符串%

正则描述

额,这个更加复杂了一点,比千分位验证的难不少。咱们先捋捋需求啊

1、对竖线前后内容进行分割
2、如果竖线在括号内则不进行分割
3、如果括号是被转义的,则不认为是括号

其实,这个需求读下来,还有一个隐藏的条件,就是如果括号不成对的时候,是很难处理的,好在题主没有这个说明,咱就当括号是严格匹配的。

这次,就不能一口气实现了,咱们分阶段实现好了

\|

print('\n'.join(re.split(r'\|','%这个一个测试2|4\)11|(0jh|96)78|8\)k|字符串% ')))
%这个一个测试2
4\)11
(0jh
96)78
8\)k
字符串% 

先按照最基本的需求,以竖线分割字符串

然后,我们将竖线限定为括号外的竖线,括号内的忽略

\|(?=[^\)]*(?:$|\|))

print('\n'.join(re.split(r'\|(?=[^\)]*(?:$|\|))','%这个一个测试2|4\)11|(0jh|96)78|8\)k|字符串% ')))
%这个一个测试2|4\)11
(0jh|96)78|8\)k
字符串% 


我们追加了一个右断言
(?=[^\)]*(?:$|\())

用来限定,竖线后边没有右括号,直到碰到另一个竖线或者字符串结束
[^\)]* 非右括号内容
(?:$|\|) 竖线或者字符串结束

然后,我们需要对转义的括号进行一下处理

\|(?=(?:[^\)]|\\\(|\\\))*(?:$|\|))


print('\n'.join(re.split(r'\|(?=(?:[^\)]|\\\(|\\\))*(?:$|\|))','%这个一个测试2|4\)11|(0jh|96)78|8\)k|字符串% ')))
%这个一个测试2
4\)11
(0jh|96)78
8\)k
字符串% 

这次,我们是对原来的 [^\)] 部分进行了一些调整,指定 \\\( 和 \\\) 可以被匹配

这个时候,这个正则就符合题主的要求了

正则测试

python 测试

print(re.split(r'\|(?=(?:[^\)]|\\\(|\\\))*(?:$|\|))','%这个一个测试2|4\)11|(0jh|96)78|8\)k|字符串% '))
['%这个一个测试2', '4\\)11', '(0jh|96)78', '8\\)k', '字符串% ']
print(re.split(r'\|(?=(?:[^\)]|\\\(|\\\))*(?:$|\|))','用|分割所有内容|(括号里的|被忽视)|如果括号\\(转义|会忽略转义\\)的括号'))
['用', '分割所有内容', '(括号里的|被忽视)', '如果括号\\(转义', '会忽略转义\\)的括号']

javascript 测试

'%这个一个测试2|4\\)11|(0jh|96)78|8\\)k|字符串% '.split(/\|(?=(?:[^\)]|\\\(|\\\))*(?:$|\|))/gi)
(5) ['%这个一个测试2', '4\)11', '(0jh|96)78', '8\)k', '字符串% ']
'用|分割所有内容|(括号里的|被忽视)|如果括号\\(转义|会忽略转义\\)的括号'.split(/\|(?=(?:[^\)]|\\\(|\\\))*(?:$|\|))/gi)
(5) ['用', '分割所有内容', '(括号里的|被忽视)', '如果括号\(转义', '会忽略转义\)的括号']

4、关于#正则表达式#的问题,如何解决?

问答地址:https://ask.csdn.net/questions/7907410/54127882?spm=1001.2014.3001.5501

正则表达式
匹配汉字中ABB类型的词组

import re
text = input()
words = re.findall(r'((.)(.)\3)',text)
print(words)

这个正则表达式能匹配ABB但是也能匹配三个相同的汉字,有没有办法让第一个汉字与第二个汉字不同

正则描述

哦吼,和第一个示例差不多的内容,不过要求前边还有一个不同的字符

来描述一下需求,很简单的

需要abb形式的内容,且a与b不得相同

那么我们已经学会分组,也学会断言了,实现起来还是很简单的

(.)(?!\1)(.)\2

多简单的实现,分组1后边不能跟和分组1相同的内容,分组2后边跟分组2相同的内容,这不就是 abb 形式了么

正则测试

python 测试


re.findall(r'((.)(?!\2)(.)\3)','add and all food zzz 宋甜甜,范若若,戚戚惨惨切切')
Out[24]: 
[('add', 'a', 'd'),
 ('all', 'a', 'l'),
 ('foo', 'f', 'o'),
 (' zz', ' ', 'z'),
 ('宋甜甜', '宋', '甜'),
 ('范若若', '范', '若'),
 (',戚戚', ',', '戚'),
 ('惨切切', '惨', '切')]

javascript 测试

'add and all food zzz 宋甜甜,范若若,戚戚惨惨切切'.match(/((.)(?!\2)(.)\3)/gi)
(8) ['add', 'all', 'foo', ' zz', '宋甜甜', '范若若', ',戚戚', '惨切切']

大体实现了题主的需求了,一些 空格标点之类的也参与了进来,无伤大雅,自己把点修改成指定的字符集即可

进阶实现

在这个示例里,老顾自己写了个字符串,戚戚惨惨切切,那么,如果要匹配 abb 形式,其实应该是有两个结果:戚惨惨,惨切切。

而正常的正则在匹配时,每个字符只能参与一次匹配,如何才能让字符参与多次匹配呢?

其实应该有小伙伴反应过来了,使用右断言啊!右断言又叫预搜索可不是白叫的哦。

那么,最后的正则也就可以想到了,用预搜索来实现 abb 组合的检索

re.findall(r'(?=((.)(?!\2)(.)\3))','add and all food zzz 宋甜甜,范若若,戚戚惨惨切切')
Out[25]: 
[('add', 'a', 'd'),
 ('all', 'a', 'l'),
 ('foo', 'f', 'o'),
 (' zz', ' ', 'z'),
 ('宋甜甜', '宋', '甜'),
 ('范若若', '范', '若'),
 (',戚戚', ',', '戚'),
 ('戚惨惨', '戚', '惨'),
 ('惨切切', '惨', '切')]

但是,这个正则是基于 python 正则匹配的特性,即:如果有分组,则所有分组结果以元组形式返回

在 c# 等支持分组的语言环境,这么写也没有问题,大不了去取第一个分组的值罢了,但是,在 js 这么写就不可行了,因为他不会返回分组的内容,而是匹配到位置了,返回一个位置信息,没有内容了!

那么 js 的正则就需要做一个大改动了。

Array.from('add and all food zzz 宋甜甜,范若若,戚戚惨惨切切'.matchAll(/(?=((.)(?!\2)(.)\3))(?=.{3})/gi)).map(x => x[1])
(9) ['add', 'all', 'foo', ' zz', '宋甜甜', '范若若', ',戚戚', '戚惨惨', '惨切切']

这里,我们用到了 es6 的一些新特性,来辅助我们获取第一个分组的内容,好在也是可以做到的

小结

现在又讲解了几个例子,结合老顾之前的几篇入门文章,相信小伙伴们已经对正则的编写有了新的体会了,那么,就放手去练习吧,只有多练多用,才会真正的掌握这些技巧。

纸上得来终觉浅,方知此事须躬行。
在这里插入图片描述

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

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

相关文章

0基础自学软件测试 用这个方法 99%的人都成功了

对于大多数0基础的小白而言&#xff0c;刚开始学软件测试&#xff0c;肯定会遇到各种各样的难题&#xff0c;有时候问题多了&#xff0c;扛不住了&#xff0c;导致最后无法坚持&#xff0c;或者学的很杂&#xff0c;学而不精。 那么有哪些比较有效的方法和技巧&#xff0c;可以…

系统分析师之数据库系统(七)

目录 一、数据库概念 1.1 数据库管理系统DBMS 1.2 数据库系统DBS 二、数据库设计 2.1 数据库设计过程 2.2 E-R模型 2.3 关系代数 2.4 规范化理论 2.4.1 价值与用途 2.4.2 函数依赖 2.4.3 键 2.4.4 范式 2.4.5 无损分解 三、并发控制 3.1 基本概念 3.2 问题示例…

SCA技术进阶系列(二):代码同源检测技术在供应链安全治理中的应用

一、直击痛点&#xff1a;为什么需要同源检测 随着“数字中国”建设的不断提速&#xff0c;企业在数字化转型的创新实践中不断加大对开源技术的应用&#xff0c;引入开源组件完成应用需求开发已经成为了大多数研发工程师开发软件代码的主要手段。随之而来的一个痛点问题是&…

开启数字化之旅:VR全景视频带你进入真实而神奇的世界

引言&#xff1a;随着科技的不断发展&#xff0c;虚拟现实技术正在成为越来越多人所追捧和体验的技术。而VR全景视频作为虚拟现实技术的一种重要应用&#xff0c;也得到了越来越多人的关注。那么&#xff0c;VR全景视频到底是什么&#xff1f;它的优势和特点是什么&#xff1f;…

OpenGL入门教程之 变化颜色的三角形

一、 知识点 &#xff08;1&#xff09;着色器 着色器(Shader)是运行在GPU上的小程序。这些小程序为图形渲染管线的某个特定部分而运行。从基本意义上来说&#xff0c;着色器只是一种把输入转化为输出的程序。着色器也是一种非常独立的程序&#xff0c;因为它们之间不能相互通…

153. 寻找旋转排序数组中的最小值

已知一个长度为 n 的数组&#xff0c;预先按照升序排列&#xff0c;经由 1 到 n 次 旋转 后&#xff0c;得到输入数组。例如&#xff0c;原数组 nums [0,1,2,4,5,6,7] 在变化后可能得到&#xff1a; 若旋转 4 次&#xff0c;则可以得到 [4,5,6,7,0,1,2] 若旋转 7 次&#xff0…

【刷题】搜索——BFS:字串变换【双向广搜模板】

双向广搜是BFS的一种优化方式&#xff0c;就是起点和终点同时往中间搜索。 假设每搜一步&#xff0c;都会有6种新的状态进入队列&#xff0c;搜索10步才能得到答案&#xff0c;总状态数是 1 6 6 2 6 3 . . . 6 9 166^26^3...6^9 166263...69。 但是假如已知终点的状态&am…

Crash分析gpu非法访问地址问题

Crash分析gpu非法访问地址问题 1. 问题描述 在我司产品monkey老化过程中&#xff0c;极低概率出现gpu驱动访问非法地址导致kernel panic问题&#xff0c;在kernel panic后&#xff0c;主动触发ramdump机制&#xff0c;抓到相关的ramdump文件&#xff0c;利用crash工具进行离线…

ggrcs包2.9版本发布----增加了绘制单独rcs曲线(限制立方样条)的singlercs函数

目前本人写的ggrcs包新的2.8版本已经在CRAN上线&#xff0c;目前支持逻辑回归&#xff08;logistic回归&#xff09;、cox回归和多元线性回归。增加了绘制单独rcs曲线&#xff08;限制立方样条&#xff09;的singlercs函数。 需要的可以使用代码安装 install.packages("…

UE4/5多人游戏详解(五、创建多人游戏插件)

目录 创建插件&#xff1a; 功能制作&#xff1a; 基础构造&#xff1a; 代码&#xff1a; 准备&#xff1a; 代码&#xff1a; 之前4个内容&#xff0c;我简单的讲解了一个项目中如何加入多人会话。 现在我们做一个插件&#xff0c;这样就不需要每一次创建项目的时候就…

CT前瞻(二):Vant4实战之Card卡片与Cell单元格

文章目录 &#x1f4cb;前言&#x1f3af;关于 Card卡片 和 Cell单元格 组件&#x1f9e9;Cell单元格&#x1f9e9;Card卡片 &#x1f3af;实战代码&#x1f4dd;最后 &#x1f4cb;前言 最近在项目开发和学习的过程中&#xff0c;涉及到了Vant UI&#xff08;简称Vant&#x…

气传导耳机和骨传导耳机的区别是啥?气传导耳机有哪些优缺点?

本文主要讲解一下气传导耳机和骨传导耳机的区别、气传导耳机的优缺点&#xff0c;并推荐一些目前主流的气传导耳机款式&#xff0c;大家可以根据自身需求&#xff0c;选择自己感兴趣的部分观看。 气传导耳机和骨传导耳机不同点&#xff1a; 气传导耳机和骨传导耳机最大且最根…

HTML+CSS+JS 学习笔记(二)———CSS

&#x1f331;博客主页&#xff1a;大寄一场. &#x1f331;系列专栏&#xff1a;前端 &#x1f331;往期回顾&#xff1a;HTMLCSSJS 学习笔记&#xff08;一&#xff09;———HTML(上) HTMLCSSJS 学习笔记&#xff08;一&#xff09;———HTML(中) HTMLCSSJS 学习笔记&#…

数字信号预处理——平滑和去噪

数字信号预处理 对信号进行去噪、平滑和去趋势处理&#xff0c;为进一步分析做好准备。从数据中去除噪声、离群值和乱真内容。增强信号以对其可视化并发现模式。更改信号的采样率&#xff0c;或者使不规则采样信号或带缺失数据信号的采样率趋于恒定。为仿真和算法测试生成脉冲…

看完这篇文章你就彻底懂啦{保姆级讲解}-----(LeetCode刷题59螺旋矩阵II) 2023.4.20

目录 前言算法题&#xff08;LeetCode刷题59螺旋矩阵II&#xff09;—&#xff08;保姆级别讲解&#xff09;分析题目&#xff1a;算法思想&#xff08;重要&#xff09;螺旋矩阵II代码&#xff1a; 结束语 前言 本文章一部分内容参考于《代码随想录》----如有侵权请联系作者删…

英码科技深元ai工作站在化工园区应用,保障安全生产

当今&#xff0c;随着工业化进程的不断推进&#xff0c;化工产业作为重要的基础产业之一&#xff0c;为社会经济发展做出了巨大贡献。然而&#xff0c;随着化工园区规模的不断扩大&#xff0c;化工园区内的安全问题和环境问题也日益突出。因此&#xff0c;如何通过科技手段提升…

网络安全文章汇总导航(持续更新)

网络安全文章汇总导航&#xff08;持续更新&#xff09; 1. 介绍1.1. 初衷1.2. 更新时段1.3.最近更新时间及内容 2. 文章列表2.1. 基础篇2.2. 工具篇2.3. 靶场安装篇2.4. 权限提升篇2.5. 漏洞复现篇2.6. 加固与排查篇2.7. APP渗透篇2.8. 其它基础篇 1. 介绍 本章主要将博客中的…

ROS学习第十二节——话题通信控制小乌龟

1.基操一下 首先打开小乌龟程序和键盘控制程序 rosrun turtlesim turtlesim_node rosrun turtlesim turtle_teleop_key 查看话题列表 rostopic list 打开计算图查看具体是那个话题在起作用 rqt_graph 从上图可以看到两个节点之间的话题是 /turtle1/cmd_vel 使用以下命令获…

从零学习SDK(7)如何打包SDK

打包SDK的目的是为了方便将SDK提供给其他开发者或用户使用&#xff0c;以及保证SDK的兼容性和安全性。打包SDK可以有以下几个好处&#xff1a; 减少依赖&#xff1a;打包SDK可以将SDK所需的库、资源、文档等打包成一个文件或者一个目录&#xff0c;这样就不需要用户再去安装或…

直播app源码,流媒体自建好还是用第三方好

随着移动互联网的发展&#xff0c;直播应用已经成为人们日常生活中的一部分。但是&#xff0c;很多人在开发自己的直播app时&#xff0c;面临一个问题&#xff1a;自建直播流媒体服务器还是使用第三方直播平台&#xff1f;在本文中&#xff0c;我们将分析这两种选择的优缺点&am…