如何写一个正则表达式

拆成(取值范围+量词)这样的组合,例如qq号码验证:号码数字5-15位,并且不以0开头

  • 拆分(1位:1-9的数字)(4-14位:0-9的数字)
  • 初步获得pattern = /[1-9][0-9]{4,14}/
  • 上述模式是正确的吗?我们可以做个测试
    1
    2
    let pattern = /[1-9][0-9]{4,14}/
    console.log(pattern.test('555555555555555555')) // 18位
    看样子pattern是错误的,它可以匹配超过15位的号码。即只要字符串中有符合该pattern的子串,就会匹配。(比如a123456b就会匹配)
  • 修改 => 加入元字符^$表示字符串的开始和结束 => pattern = /^[1-9][0-9]{4,14}$/

常见使用方法以及案例

1. 移除className - 元字符\b

使用元字符\b\b匹配单词的开始或结束)匹配要移除的className

1
2
3
4
5
6
7
8
<script type="text/javascript">
/*要求将下面这个元素中的unabled类移除掉*/
<div class="confirm-btn unabled mb-10" id="j_confirm_btn">提交</div>
var classname = document.getElementById("j_confirm_btn").className;
// \b表示单词的开头或结尾
var newClassName = classname.replace(/\bunabled\b/,"");
document.getElementById("j_confirm_btn").className = newClassName;
</script>

2. 找句子中hi后面不远处跟着一个Lucy那一段 - 元字符\b

.匹配除换行符以外的任意字符,*表示重复零次或多次,那么.*表示单词hi和单词Lucy中间有0个或多个字符

1
\bhi\b.*\bLucy\b

3. 把一串数字表示成千位分隔形式 - 正向预查a(?=b)

  • 从后往前匹配三个数字 pattern = /(\B\d{3})+$/g
  • 利用正向预查匹配前面的空格 pattern = /(?=(\B\d{3})+$)/g
    1
    2
    3
    let num = 100000000
    // \B匹配不是单词开头或结束的位置
    console.log(num.toString().replace(/(?=(\B\d{3})+$)/g, ','))
    可以利用replace的第二个参数查看具体匹配详情
    1
    2
    3
    4
    5
    6
    7
    8
    let num = 100000000
    // \B匹配不是单词开头或结束的位置
    console.log(num.toString().replace(/(?=(\B\d{3})+$)/g, function (...params) {
    console.log(params)
    return ','
    }
    ))
    // 可以看到输出两次
    把一串数字表示成千位分隔形式

正则的正向预查和反向引用

4. 国内电话号码验证 - 分支条件|

  • 验证国内电话号码,例如0555-6581752、021-86128488
    拆分:
    • 0开头
    • 后接3个数字+‘-’+7个数字(非0开头)或者2个数字+‘-’ +8个数字(非0开头)
      1
      pattern = /(^0[0-9]{3}-[1-9][0-9]{6}$)|(^0[0-9]{2}-[1-9][0-9]{7}$)/
      使用\d代表[0-9]
      1
      pattern = /(^0\d{3}-[1-9]\d{6}$)|(^0\d{2}-[1-9]\d{7}$)/

      5. 分组与捕获

      1
      2
      3
      4
      5
      6
      7
      // 匹配abab
      console.log(/(ab){2}/.test('ababcc')) // 此处将ab重复两次
      // 匹配所有js与css文件
      // 限定分支
      console.log(/.*\.(js|css)$/.test('hello.js'))
      // 获取js或css文件名
      console.log('hello.js'.replace(/(.*)\.(js|css)$/, '$1'))

      6. 获取链接https://www.baidu.com?name=astar&age=200中name的值

  • [^x]匹配除了x以外的任意字符
  • [^aeiou]匹配除了aeiou这几个字母以外的任意字符,<a[^>]+> 匹配用尖括号括起来的以a开头的字符串,例如<as>
  • ()代表分组
    1
    2
    3
    4
    5
    6
    7
     function getParam(attr) {
    // window.location.search => ?name=astar&age=100
    let pattern = new RegExp(`[?&]${attr}=([^&]*)`)
    let match = pattern.exec(window.location.search)
    return match && decodeURIComponent(match[1])
    }
    console.log(getParam('name'))
    ps: decodeURIComponent() 函数可对 encodeURIComponent() 函数编码的 URI 进行解码。

在这里插入图片描述

7. 获取url中的所有参数

1
2
3
4
5
6
7
8
9
10
11
function getParams (url) {
let reg = new RegExp(/[?&]([^&]*)=([^&]*)/, 'g')
let res = {}
url.replace(reg, function (str, a, b) {
res[decodeURIComponent(a)] = decodeURIComponent(b)
return str
})
return res
}
let url = 'https://www.baidu.com?name=astar&age=200'
console.log(getParams(url))

8. 正则从2018-10-07T11:48:47 Asia/zh-cn 提取出来结果[2018,10,07,11,48,47]

1
2
str.match(/\d{1,}/g)
str.match(/\d+/g)

9. 反向引用

\number\k,使用方法不同,效果一致。

  • \b(\w+)\b\s+\1\b可以用来匹配重复的单词,像go go, 或者kitty kitty(\1表示分组1匹配的文本)
  • \b(?<Word>\w+)\b\s+\k<Word>\b自定义分组名为Word

10. 变量名转为驼峰法

1
2
3
4
5
function toCamel (s) {
return s.replace(/-\w/g, function(x) {
return x.slice(1).toUpperCase();
})
}

11. 其他练习题集锦

面试中会遇到的正则题

各类符号及其含义

元字符

字符说明
.匹配除换行符以外的任意字符
\w匹配字母或数字或下划线或汉字 [a-zA-Z0-9_]
\s匹配任意的空白符 [\r\n\t\f]
\d匹配数字
\b匹配单词的开始或结束
^匹配字符串的开始
$匹配字符串的结束

反义

字符说明
\W匹配任意不是字母,数字,下划线,汉字的字符
\S匹配任意不是空白符的字符
\D匹配任意非数字的字符
\B匹配不是单词开头或结束的位置
[^x]匹配除了x以外的任意字符
[^aeiou]匹配除了aeiou这几个字母以外的任意字符

重复限定符

字符说明
*重复零次或更多次
+重复一次或更多次
?重复零次或一次
{n}重复n次
{n,}重复n次或更多次
{n,m}重复n到m次

标志符号

字符说明
g全局模式
i不区分大小写
m多行模式

常见分组语法

分类代码/语法说明
捕获(exp)匹配exp,并捕获文本到自动命名的组里
捕获(?exp)匹配exp,并捕获文本到名称为name的组里,也可以写成(?’name’exp)
捕获(?:exp)匹配exp,不捕获匹配的文本,也不给此分组分配组号
零宽断言(?=exp)匹配exp前面的位置
零宽断言(?<=exp)匹配exp后面的位置
零宽断言(?!exp)匹配后面跟的不是exp的位置
零宽断言(?<!exp)匹配前面不是exp的位置
注释(?#comment)这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读

懒惰限定符

代码/语法说明
*?重复任意次,但尽可能少重复
+?重复1次或更多次,但尽可能少重复
??重复0次或1次,但尽可能少重复
{n,m}?重复n到m次,但尽可能少重复
{n,}?重复n次以上,但尽可能少重复

RegExp实例方法

exec()

该方法是专门为捕获组设计的。

接收字符串参数,返回包含第一个匹配项信息的数组;或者在没有匹配项的情况下返回null。返回的数组虽然是Array的实例,但包含两个额外的属性:index和input。其中,index表示匹配项在字符串中的位置,而input表示应用正则表达式的字符串。
即使正则表达式设置了全局,每次也只会返回一个匹配项,需要多次调用exec()方法。

1
2
3
4
5
6
7
8
9
10
11
12
var text = 'mom and dad and baby'
var pattern = /mom (and dad (and baby)?)?/gi
var matches = pattern.exec(text)
console.log(matches)
// [
// 'mom and dad and baby',
// 'and dad and baby',
// 'and baby',
// index: 0,
// input: 'mom and dad and baby',
// groups: undefined
//]

test()

返回true或false

接收字符串参数,在模式与该参数匹配的情况下返回true,否则返回false。
test方法经常出现在验证用户输入的情况下,因为我们只想知道输入是不是有效,至于他为什么无效就无关紧要了。

1
2
3
4
var text = '000-00-0000'
var pattern = /\d{3}-\d{2}-\d{4}/
var matches = pattern.test(text)
console.log(matches) // true

字符串的方法

match()

返回匹配的内容组成的数组,失败返回null

返回第一个匹配成功的字符串片段开始的位置,失败则返回-1

replace()

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

split()

把一个字符串分割成数组

【参考】

不完全正则指南

正则表达式30分钟入门教程

javascript replace高级用法

JS正则表达式完整教程(略长)

感谢您的阅读,本文由 Astar 版权所有。如若转载,请注明出处:Astar(http://example.com/2022/01/14/%E4%BB%8E%E5%B8%B8%E8%A7%81%E6%A1%88%E4%BE%8B%E6%8E%A2%E7%B4%A2JS%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%94%A8%E6%B3%95/
模拟实现call、apply和bind
前端生成CHANGELOG指南