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

这篇具有很好参考价值的文章主要介绍了如何才能写出一个符合预期的正则?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

正则表达式入门

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

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

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

《文盲的正则表达式入门》
《揭开正则表达式的神秘面纱》
《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 的一些新特性,来辅助我们获取第一个分组的内容,好在也是可以做到的

小结

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

纸上得来终觉浅,方知此事须躬行。
如何才能写出一个符合预期的正则?文章来源地址https://www.toymoban.com/news/detail-420345.html

到了这里,关于如何才能写出一个符合预期的正则?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【编译原理】【词法分析】【正则表达式】【NFA】【DFA】【C++】正则表达式转DFA&NFA,判断字符串是否符合正则表达式的匹配算法

    显然,正则表达式、NFA、DFA的概念都很简单,所以直接上代码,注释应该解释地比较清楚, 没有万能头文件的自行替换需求库 ,如果有疑问的可以留言。 网盘链接 [自行补全]/s/1pbGT_wpB662TwFrnukXgGQ?pwd=TSIT 提取码:TSIT 原理可以参考这篇博客 传送门 本次程序由四个文件组成 文

    2024年02月11日
    浏览(88)
  • js中如何在正则表达式中放入一个变量呢

    工作中碰见了这样的业务 因为平常写的正则 喜欢 直接 // 写正则匹配的表达式 突然有一天 我的正则表达式要从一个 变量中 取到 跟往常的有点不用 假设 var name = “zhao” var str = “hello world zhao aaa”; 想找到 zhao在字符串中位置 然后 zhao我又是定义了一个变量 才这样的 var a

    2023年04月17日
    浏览(75)
  • [职场] 求职如何设置预期 #笔记#经验分享

    求职如何设置预期 在求职的道路上,无论处于哪个年龄阶段,合理的就业期望值才能使我们的愿望与社会的需求相吻合,才能让自己在今后的工作中发挥出最大的实力与能力。 一、结合测评软件,明确求职目标 根据霍兰德职业兴趣测试结果,偏向于什么型人格,最好就寻求

    2024年02月21日
    浏览(45)
  • 大牛练成记:用JavaScript徒手写出一个日期选择插件

    🏆作者简介,黑夜开发者,全栈领域新星创作者✌,阿里云社区专家博主,2023年6月csdn上海赛道top4。 🏆本文已收录于专栏:100个JavaScript的小应用。 🎉欢迎 👍点赞✍评论⭐收藏 在现代Web应用程序中,日期选择器是一个非常常见的组件,用户可以使用它来选择特定的日期。

    2024年02月14日
    浏览(30)
  • 手把手教你写出第一个C语言程序

    大家好,我是努力学习游泳的鱼。这篇文章将手把手带你写出人生中第一个C语言程序, Hello, World 。在阅读本文之前,建议先百度 visual studio ,在微软官网下载并安装VS的最新版本,安装时记得勾选“C++桌面开发”选项。 2.1 环境 工欲善其事必先利其器,我们需要写C语言代码

    2024年02月10日
    浏览(58)
  • java生成一个符合密码学和安全性的随机秘钥

    有时 我们在生成token 或者完成某种加密形式时会需要一个秘钥 但是 有些时候 项目开发并没有规定用什么秘钥 但是 秘钥都是要有一定格式规范的 我们可以通过以下代码生成一个随机秘钥 重点是 这种一定会符合密码学和安全规范

    2024年02月07日
    浏览(41)
  • 如何写出高质量代码?

    作为一名资深开发人员,写出高质量的代码是我们必须要追求的目标。然而,在实际开发中,我们常常会遇到各种问题。比如,代码的可读性、可维护性、健壮性和灵活性等,这些都会影响代码的质量。那么,究竟如何才能写出高质量的代码呢? 代码结构清晰易懂,能够使代

    2024年02月02日
    浏览(58)
  • 如何规范写出 README 模板?

    README 标准是由 RichardLitt 发起,十多名开发者共同贡献完成的,在 GitHub 上有 1230+ Star:standard-readme 标准 README 实例: standard-readme/tree/main/example-readmes 奖励:实例 本文模板获取地址: README-Template README 文件是人们通常最先看到的第一个东西。它应该告诉人们为什么要使用、如

    2024年02月11日
    浏览(34)
  • 如何写出高质量代码

    一、 前言 编写高质量代码是每一位程序员的追求。高质量的代码可以提高代码可读性、可维护性、可扩展性以及软件运行的性能和稳定性。在这篇文章中,我将分享一些编写高质量代码的特征、编程实践技巧和软件工程方法论。 可读性:好的代码应该能够被维护者轻易地理

    2024年02月02日
    浏览(88)
  • 会自动写代码的AI大模型来了!仅10秒就写出一个飞机大战游戏!

    昨天分享了一款可以帮我们写代码的插件 CodeGeex ,其实能帮我们解决大部分问题,讲道理已经很好了对不对? but ,他就是最好的插件吗? 肯定不是,这不又让我又发现了一款可以平替的插件 TONGYI Lingma (阿里云出品智能编码助手通义灵码)。 可能有同学会问了,那六哥这

    2024年02月06日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包