js 字符串替换_正则精要:玩转JS正则表达式,也许只需这一篇(建议收藏)

0.导引

在正文开始前,先说说正则表达式是什么,为什么要用正则表达式?正则表达式在我个人看来就是一个程序可以识别的规则,有了这个规则,程序就可以帮我们判断某些字符是否符合我们的要求。但是,我们为什么要使用正则表达式呢?下面来看个正则业务场景,来验证一串字符是否为合法QQ号。示例如下:

/*** 要求:一个合法的QQ号必须满足:1、5-15位;2、全是数字;3、不以0开头*///1.在不使用正则表达式的时候,我们可能会这样判断QQ号的合法性var qq="6666666a6666";         if(qq.length>=5&&qq.length<=15&&!isNaN(qq)&&qq.charCodeAt(0)!=48){        alert("QQ合法");    }else{        alert("QQ不合法")    }    //2.使用正则表达式    var qq="066336";    var reg=/^[1-9][0-9]{4,14}$/;    if(reg.test(qq)){        alert("QQ合法");    }else{        alert("QQ不合法");    }

从上面这个例子可以看出来使用了正则表达式的时候,我们的代码量变少了,而且比较直观。如果遇到非常的复杂的匹配,正则表达式的优势就更加明显了。

e8b990996a057800c23addfe15136d67.png

那什么是正则表达式呢?

1.正则定义

也就是创建正则表达式对象,可通过字面量形式或RegExp构造函数两种形式来定义,如下所示:

// 字面量定义const pattern=/d/g//或 构造器定义const pattern = new RegExp('d','g')

一般使用字面量形式,构造函数形式用在正则表达式在运行时才能确定下的情况,例如

function hasClass(ele, classname) {    const pattern = new RegExp('(^|s)' + classname + '(s|$)')    return pattern.test(ele.className)}

注意:字符串中反斜杠有别的含义,要想表示d等要使用两个反斜杠来转义d* 。

第一种通过"/正则表达式/修饰符"这种形式直接写出来;

第二种通过“new RegExp('正则表达式','修饰符')”创建一个RegExp对象。

其中修饰符为可选项,有三个取值分别为:g为全局匹配;i指不区分大小写;m指多行匹配。

通过上述方式,就创建了正则表达式对象。说到RegExp对象,下面要说一下RegExp对象自带的属性,并不复杂,这里我就列一下,不做展开。

c5d5499084cd23300e2969e28c0b507c.png

2.符号及应用解析

4c59d2a0e19b0732c6eb5a7c453d4662.png

1)反斜杠

在正则表达式中反斜杠有重要的含义

  • 是用来转义有特殊含义的字符,比如 [、^、.等。例如,要想只匹配.com 需要
         /.com/.test('.com')
  • 预定的字符类以开始,比如 d w s

而在字符串中反斜杠同样是一个转义字符,比如结合n r t来表示换行、回车、制表位等

要想在字符串中表示出一个,则表达式中需要两个 ,示例如下:

new RegExp("[w.]").toString()=='/[w.]/'

2)()、[]与|

[]:集合操作符,表示一系列字符的任意一个

例如:/[abc]/ 表示a、b、c中的任意一个能匹配就可以了

关于/[a|b]/

一个常见的误区是感觉/[a|b]/表示要匹配a或者b,其实是a、b或者|中的任意一个

/[a|b]/.test('|') === true/(a|b)/.test('|') ===false

关于括号()

从上面可以看到,圆括号中的|是或的意思,表示要匹配()以|分割的两边的整体(两边其中之一),注意是整体。

例子:

/(abc|abd)/.test('ab') ===false/(abc|abd)/.test('abc') ===true/(abc|abd)/.test('abd') ===true

3)分组与捕获
上面只是介绍了圆括号中存在|时需注意的点,这里重点说一下圆括号(英文状态下的小括号())

在正则中,圆括号有两种含义,一是用来分组,一是用来捕获想要的值

  • 分组

()结合* ? + {} 使用时,是对圆括号内的整体进行repeat

/(ab)+/ 匹配一个或多个ab/(ab)+|(cd)+/ 匹配一个或多个 ab或cd
  • 捕获

捕获是一个强大的功能,也是很多时候我们使用正则的原因,同样以()来表示

例子:找出样式中的透明度值

function getOpacity(elem) { var filter = elem.style.filter; if(filter){ return filter.indexOf("opacity=") >= 0 ?(parseFloat(filter.match(/opacity=([^)]*)/)[1]) / 100) + "" : "" } return elem.style.opacity}

捕获主要结合exec()、match() 和 g标记使用,下面会介绍

需要强调的是,因为分组和捕获一样使用(),所以,在一个正则表达式中既有用于分组的(),也有用于捕获的()时,对于分组部分,可以加上?:,这样,结果集就只包含我们想要捕获的部分。

示例如下:

'
hahahahah
'.match(/(]+>)([^ [
hahahahah ,
, hahahahah ] //两个捕获如果我们只对标签内的文本感兴趣'
hahahahah
'.match(/(?:]+>)([^ [
hahahahah , hahahahah ] //对于
,我们不关心,就不要了

说到?: 就要提一下长得差不多的 ?= 和 ?!

?= 表示后面必须跟着某些东西,并且结果中不包含?=指定的部分,并且不捕获

?! 表示后面必须不跟着某些东西

对比看一下

/a(?:b)/.exec('abc')> ["ab", index: 0, input: "abc"] //注意匹配的是"ab"/a(?=b)/.exec('abc')> ["a", index: 0, input: "abc"] //注意匹配的只是"a"/a(?!b)/.exec('abc')> null //没有匹配的,返回的是null

再看个例子,数字字符串转千分位

function formatNumber(str) {  return str.replace(/B(?=(d{3})+$)/g, ',')}formatNumber("123456789")> 1,234,567,890

解释:

B表示除了字符串首字母之前的边界,比如1和2之间的边界,2和3之间的边界等后面()中的?=(d{3})+$表示上面提到的那些边界后面必须跟着3N个数字直到字符串尾部g表示全局匹配,即每个上面说的边界都要检测2,如果符合,replace把边界替换成,

4)exec()、match()与g标记

exec()和match()都是返回数组,结果集中包含捕获的内容

在正则中不包含g时,exec()和match()返回的结果集是一样的,数组中依次是 整个匹配的字符串、依次的()指定的要捕获的部分

54e6743746fe619247c626759c9d2b64.png

在有g的时候,match()返回的数组中的每一项是依次匹配到的整体字符串,不包含每个匹配中捕获到的内容

对比来看

"p123 q123".match(/b[a-z]+(d+)/)> ["p123", "123", index: 0, input: "p123 q123"]"p123 q123".match(/b[a-z]+(d+)/g)> ["p123", "q123"]

可以看到加上g后,返回的数组就只有匹配项了

那么,即想匹配全部,又想获取到捕获怎么办呢?

while与exec()结合

let pattern=/b[a-z]+(d+)/glet str='p123 q123'let matchwhile((match=pattern.exec(str)) !=null){    console.log(match)}> ["p123", "123", index: 0, input: "p123 q123"]  ["q123", "123", index: 5, input: "p123 q123"]

5)replace()

对于字符串的replace方法,重点说一下,其第二个参数,可是一个函数。

对于str.replace(/xxxxx/g,function(){})

函数在每次前面的正则匹配成功时都会执行,函数的参数依次是,完整的匹配文本、依次的捕获部分、当前匹配的索引、原始字符串

"border-bottom-width".replace(/-(w)/g,function(match,capture){    return ";"+capture.toUpperCase()})> "border;Bottom;Width"

注意,有人可能把其中的第二个函数参数改写成箭头函数,如(..)=>{..}则可能会出错,需要当心。

4c45811838058e1f9bf903b9f60bd165.png

3.应用精要

有了上面的认知和解析,这里再总结一下正则对象(包括两种方式创建的对象)的主要方法。

1.test()

检索字符串中指定的值。返回 true 或 false。这个是我们平时最常用的方法。

 var reg=/hello w{3,12}/; alert(reg.test('hello js'));//false alert(reg.test('hello javascript'));//true

2.exec()

检索字符串中指定的值。匹配成功返回一个数组,匹配失败返回null。

var reg=/hello/;console.log(reg.exec('hellojs'));//['hello']console.log(reg.exec('javascript'));//null

3.compile()

compile() 方法用于改变正则。compile() 既可以改变检索模式,也可以添加或删除第二个参数。

var reg=/hello/;console.log(reg.exec('hellojs'));//['hello']reg.compile('Hello');console.log(reg.exec('hellojs'));//nullreg.compile('Hello','i');console.log(reg.exec('hellojs'));//['hello']

正则表达式拓展

除了RegExp对象提供方法之外,String对象也提供了四个方法来使用正则表达式,在使用JavaScript时,也常用到。

1.match()

在字符串内检索指定的值,匹配成功返回存放匹配结果的数组,否则返回null。这里需要注意的一点事,如果没有设置全局匹配g,返回的数组只存第一个成功匹配的值。

var reg1=/javascript/i;var reg2=/javascript/ig;console.log('hello Javascript Javascript Javascript'.match(reg1));//['Javascript']console.log('hello Javascript Javascript Javascript'.match(reg2));//['Javascript','Javascript','Javascript']

2.search()

在字符串内检索指定的值,匹配成功返回第一个匹配成功的字符串片段开始的位置,否则返回-1。

var reg=/javascript/i;console.log('hello Javascript Javascript Javascript'.search(reg));//6

3.replace()

替换与正则表达式匹配的子串,并返回替换后的字符串。在不设置全局匹配g的时候,只替换第一个匹配成功的字符串片段。

var reg1=/javascript/i;var reg2=/javascript/ig;console.log('hello Javascript Javascript Javascript'.replace(reg1,'js'));//hello js Javascript Javascriptconsole.log('hello Javascript Javascript Javascript'.replace(reg2,'js'));//hello js js js

4.split()

把一个字符串分割成字符串数组。

var reg=/1[2,3]8/;console.log('hello128Javascript138Javascript178Javascript'.split(reg));//['hello','Javascript','Javascript178Javascript']

4.两例实战

第一次接触正则表达式同学们,可能被这个正则表达式的规则弄得迷迷糊糊的,根本无从下手。小编我第一次学这个正则表达式的时候,也是稀里糊涂,什么元字符、量词完全不知道什么东西,云里雾里的。后面小编细细研究了一下,总结一套方法,希望可以帮助大家。

关于正则表达式书写规则,可查看w3school,上面说的很清楚了,我就不贴出来了。我就阐述一下我写正则表达式的思路。

其实正则表达式都可以拆成一个或多个(取值范围+量词)这样的组合。针对每个组合我们根据JS正则表达式的规则翻译一遍,然后将每个组合重新拼接一下就好了。下面我们举个例子来试一下,看看这个方法行不行。

验证QQ号的合法性

合法qq号规则:1、5-15位;2、全是数字;3、不以0开头

第一步:拆成(取值范围+量词)这样的组合

根据QQ号的验证规则,我们可以拆成两个(取值范围+量词)的组合。分别是:

1.(1~9的数字,1个);2.(0~9的数字,4~14个)
第二步:根据正则表达式规则翻译(取值范围+量词)
1.(1~9的数字,1个)     =>   [1-9]{1}或者[1-9]2.(0~9的数字,4~14个)  =>   [0-9]{4,14}
第三步:将翻译好的(取值范围+量词)组合进行拼接

初学者可能在拼接这一步会犯一个错误,可能会组合拼接成这个样子/[1-9]{1}[0-9]{4,14}/或者简写翻译成/[1-9] [0-9]{4,14}/这些都不对的。调用test()方法的时候,你会发现只要一段字符串中有符合正则表达式的字符串片段都会返回true,童鞋们可以试一下。

var reg=/[1-9][0-9]{4,14}/;alert(reg.test('0589563'));//true,虽然有0,但是'589563'片段符合alert(reg.test('168876726736788999'));//true,这个字符串长度超出15位,达到18位,但是有符合的字符串片段

正确的写法应该是这样的:

/^[1-9][0-9]{4,14}$/(用^和$指定起止位置)

下面我们看一个复杂点的例子:

验证国内电话号码

0555-6581752、021-86128488

第一步:拆成(取值范围+量词)这样的组合

这里会拆成两个大组合:

1、(数字0,1个)+(数字0~9,3个)+("-",1个)+(数字1~9,1个)+(数0~9,6个)2、(数字0,1个)+(数字0~9,2个)+("-",1个)+(数字1~9,1个)+(数0~9,7个)
第二步:根据正则表达式规则翻译(取值范围+量词)
1、([0-0],{1})+([0-9],{3})+"-"+([1,9],{1})+([0,9],{6})2、([0-0],{1})+([0-9],{2})+"-"+([1,9],{1})+([0,9],{7})
第三步:将翻译好的(取值范围+量词)组合进行拼接

这里我们先拼接一个大组合,然后再将大组合拼接起来

1、0[0-9]{3}-[1-9][0-9]{6}2、0[0-9]{2}-[1-9][0-9]{7}

最后拼接为:

/(^0[0-9]{3}-[1-9][0-9]{6}$)|(^0[0-9]{2}-[1-9][0-9]{7}$)/

最后

正则表达式并不难,懂了其中的道道和套路——所谓的核心和精要之后,一切都会变得简单。

另外,说点题外话——网上不乏一些文章记录一些常用的正则表达式,然后新手前端在使用正则表达式的时候都会直接拿来就用。在这里我想说一下自己的看法,这些所谓记录常用的正则表达式文章并非完全都是正确的,有不少都是错的,也可能是无心的,就像我们经常在网上看到的示例,你怎么也跑不通。所以同学们在日后使用的过程尽量自己写正则表达式,多写写练练和总结,实在不会了可以去参考一下,但真的不要照搬下来。咱不说这种会影响自己成长的话,咱就说你抄的一定都是对的吗?多动手,多思考一下,总没有坏处的。

参考:

正则入门:https://segmentfault.com/a/1190000009324194;
正则要点:https://segmentfault.com/a/1190000012705245

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

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

相关文章

小米平板android最新版本,想要翻身还需努力 小米平板2安卓版评测

1依旧发烧&#xff1f;小米平板2评测如今的平板市场虽不能用日薄西山来形容&#xff0c;但各大厂商费尽心机惨淡经营也无力阻止平板电脑市场的衰落&#xff0c;iPad Air和Mini系列的销量下滑迫使苹果不得不用寄希望于iPad Pro打开一片新天地&#xff0c;而在手机行业风生水起了…

android 滑动过程 触发,android 代码实现模拟用户点击、滑动等操作

/*** 模拟用户点击** param view 要触发操作的view* param x 相对于要操作view的左上角x轴偏移量* param y 相对于要操作view的左上角y轴偏移量*/private static void analogUserClick(View view, float x, float y) {if (view null) {return;}LogUtil.e(TAG_POINT, "正在…

国内计算机类APP相关竞赛总结

中国高校计算机大赛–移动应用创新赛 http://www.appcontest.net/ 中国高校计算机大赛—移动应用创新赛”旨在促进高校计算机课程教学内容和教学方法改革&#xff0c;激发学生创新意识&#xff0c;提升学生利用计算机分析问题、解决问题的能力&#xff0c;特别是移动应用的设计…

flink 写kafka_flink消费kafka的offset与checkpoint

生产环境有个作业&#xff0c;逻辑很简单&#xff0c;读取kafka的数据&#xff0c;然后使用hive catalog&#xff0c;实时写入hbase&#xff0c;hive&#xff0c;redis。使用的flink版本为1.11.1。为了防止写入hive的文件数量过多&#xff0c;我设置了checkpoint为30分钟。env.…

论文阅读:超高分辨率图像中快速、准确的条码检测

摘要 由于目标对象的尺度不同&#xff0c;超高分辨率 (UHR) 图像中的对象检测长期以来一直是计算机视觉中的一个具有挑战性的问题。在条码检测方面&#xff0c;将 UHR 输入图像调整为更小的尺寸通常会导致相关信息的丢失&#xff0c;而直接处理它们的效率很高且计算成本很高。…

android 多线程 场景,精选Android初中级面试题 (三): 深探Handler,多线程,Bitmap

码个蛋(codeegg) 第 930 次推文作者&#xff1a;Focusing链接&#xff1a;https://juejin.im/post/5c85cead5188257c6703af47Handler1、谈谈消息机制Handler作用 &#xff1f;有哪些要素 &#xff1f;流程是怎样的 &#xff1f;参考回答&#xff1a;负责跨线程通信&#xff0c;…

python计算bmi的编程_Python学习-计算BMI的小程序

示例&#xff1a;小明身高1.75&#xff0c;体重80.5kg。请根据BMI公式(体重除以身高的平方)帮小明计算他的BMI指数&#xff0c;并根据BMI指数&#xff1a;低于18.5&#xff1a;过轻18.5-25&#xff1a;正常25-28&#xff1a;过重28-32&#xff1a;肥胖高于32&#xff1a;严重肥…

通过超分辨率重构来提高二维码的对比度

1 问题描述 &#xff08;1&#xff09;图像分辨率小。例如一些嵌入在海报&#xff08;如图1&#xff09;或远距离拍摄的码&#xff0c;其分辨率远小于通常情况下的码图像。 图1.海报中的二维码占比很小 &#xff08;2&#xff09;图像质量较低。有很多是经过了多次的压缩和转…

android web 访问数据库,Web下的JDBC访问数据库的基本步骤

Web下的JDBC访问数据库的基本步骤(2012-06-02 12:09:33)在Java程序中连接数据库的一般步骤分为一下几部分&#xff0c;我摘录出来&#xff0c;跟大家分享。(1)将数据库的JABC驱动加载到classpath中&#xff0c;在基于JavaEE的Web应用开发过程中&#xff0c;通常把JDBC驱动放在W…

linux 磁盘扩容_记录一次ESXi Linux在线扩容,不重启系统

因为工作需要&#xff0c;需要将运行在ESXi主机上面的一台Centos 里面的一个LV卷进行扩容&#xff0c;下面记录了此次扩展的详细过程&#xff0c;整个过程&#xff0c;不需要重启服务器。1. 首先通过df-h 查看当前磁盘结构如下&#xff1a;我们此次的最终目标&#xff0c;就是将…

我目前的主要研究方向

推荐系统 https://blog.csdn.net/search_129_hr/article/details/118680185 游戏难度动态调整 https://blog.csdn.net/search_129_hr/article/details/119204173 睡眠声音识别与增强 https://blog.csdn.net/search_129_hr/article/details/118568452 二维码图像识别与增强…

linux的任务计划6,Linux计划任务

Linux计划任务&#xff1a;未来的某个时间执行一次任务&#xff0c;或者周期性执行某个任务&#xff0c;执行结果会通过邮件通知定时任务&#xff1a;at batch周期性任务&#xff1a;crontab系统任务调度&#xff1a;/ect/crontab用户任务调度&#xff1a;/var/spool/cronmail​…

aws python lambda_python – AWS Lambda发送HTTP请求

这可能是一个简单回答的问题,但我似乎无法弄明白.背景&#xff1a;我有一个python Lambda函数来获取数据库中的更改,然后使用HTTP将json中的更改发布到URL.我正在使用urllib2这样&#xff1a;# this runs inside a loop, in reality my error handling is much betterrequest …

标签分布学习相关研究

1 标记增强及标签分布学习 https://mp.weixin.qq.com/s/cXiR-UeJkcdkljJvE2eERw http://palm.seu.edu.cn/xgeng/files/sc-info18.pdf https://baijiahao.baidu.com/s?id1687693358774525583&wfrspider&forpc https://blog.csdn.net/weixin_42001089/article/details/…

android item三种,Android RecyclerView中的ItemDecoration的几种绘制方法

如题&#xff0c;我们使用recyclerview的时候&#xff0c;如果没有设置显示条目的margin&#xff0c;或者padding的话&#xff0c;是没有分割线效果的。那么除去使用margin或padding,其余的方法是用itemdecoration绘制分割线我们绘制分割线的时候通常会使用drawable去绘制&…

上传文件和提交textfield_0基础掌握Django框架(37)文件上传

为了更好的学习效果&#xff0c;请搭配视频教程一起学习&#xff1a;Django零基础到项目实战 - 网易云课堂​study.163.com文件上传&#xff1a;文件上传是网站开发中非常常见的功能。这里详细讲述如何在Django中实现文件的上传功能。前端HTML代码实现&#xff1a;在前端中&…

2021年第3周LDL方向的周报

LDL小组&#xff1a; 如何快速进入研究状态 &#xff08;1&#xff09;系列性的工作&#xff0c;papermaker&#xff1a;读文献&#xff0c;顶刊顶会&#xff0c;综述性文章–》进行扩展&#xff0c;研究主线 &#xff08;2&#xff09;接手师兄师姐的工作–》并且对已有的工作…

2021年第3周人工智能方向的周报

快速进入研究&#xff1a; &#xff08;1&#xff09;读文献–》综述性的文献–》你自己去综述性文献 &#xff08;2&#xff09;已有的工作 &#xff08;3&#xff09;有没有相关的数据&#xff1f; 下一步事情&#xff1a; &#xff08;1&#xff09;想一想自己的横向做什么…

华为p10刷原生android,华为p10怎么刷机 华为p10刷机方法【详细介绍】

喜欢折腾手机的用户一定对于手机root权限获取不陌生&#xff0c;root后虽然不能享受官方联保服务但同时带来的好处不用小编多说。前面给大家介绍了 华为p10 刷入第三方recovery教程&#xff0c;现在华为p10刷机包已经放出来&#xff0c;小编给大家带来华为p10刷机权限获取教程。…

pythoncookie自动模拟登录_用Python模拟技巧带你实现自动抽屉登录自动点赞

原标题&#xff1a;用Python模拟技巧带你实现自动抽屉登录&自动点赞/1 前言/嘿&#xff0c;各位小伙伴们晚上好呀&#xff0c;今天小编又给大家带来干货内容啦,今天带来的是,如何自动登录抽屉&#xff0c;并且点赞&#xff01;原计划是不打算使用selenium的&#xff0c;但是…