Go to comments

Souffle js 正则表达式笔记

正则表达式 Regular Expression 在 js 代码中简写为 regexp,

1. 重点它是一个表达式,

2. 正则是表达式的修饰词,

3. 整体“正则表达式”的意思是符合一个规则的表达式,主要作用是对字符串进行操作、过滤、以及检索校验的一种规则


一、正则表达式的定义方式

用户名的校验规则

1. 监听 oninput 输入事件,每次输一个字符都会触发

2. 要求用户名必须以“数字、字母、下划线”这三种之一开头


1、不用正则表达式

获取 input 框输入的值 str[0] 是字符串类型

如果调用 number() 方法转化,输入数字返回数字,输入字母返回的是 NaN,这样判断 26 个字符就比较麻烦了

<input type="text" id="username"/>
<div id="msg"></div>

<script>

  var username = document.getElementById('username');
  var msg = document.getElementById("msg");

  username.oninput = function(){
    checkedFun(this.value);
  }

  function checkedFun(str){
    console.log(typeof str[0]); // 返回的都是字符串string类型
    console.log(Number(str[0])); // 调用number()方法返回数字或NaN
  }
  
</script>

 

2、正则表达式对字符串是如何定义和匹配的

正则表达式的定义有两种方式

1. 直接字面量 var reg = /abc/

2. 构造函数 var reg = new RegExp('abc')


正则表达式匹配使用的方法

方法名说明示例
RegExp 对象方法
complie编译正则表达式(就是改变这个正则表达式)
exec检索字符串中指定的值,返回找到的值,并确认其位置
test检索字符串中指定的值,返回布尔值reg.test(str)
字符串方法
search检索正则表达式相匹配的值
match查找所有符合正则匹配条件的结果str.match(reg)
replace替换正则表达式匹配的字符串
split把字符串分割成数组


 ^[\dA-z_]  直接字面量定义正则表达式

^ 表示以方括号里面的字符开头

[] 方括号代表一个字符(我们要匹配的一个字符),这一个字符可以是数字 \d,可以是字母 A-z,也可以是 _ 下划线


使用字符串上的 match() 方法实现正则的匹配

1. 输入 abc 匹配成功,返回的是符合规则的的子字符串 ['a', index: 0, input: 'abc', groups: undefined]

2. 输入空格或中文返回 null,表示不符合匹配规则

<input type="text" id="username"/>
<div id="msg"></div>

<script>

  var username = document.getElementById('username');
  var msg = document.getElementById("msg");

  username.oninput = function(){
    checkedFun(this.value);
  }

  function checkedFun(str){
    var reg = /^[\dA-z_]/;
    if(str.match(reg)){
      msg.innerText = "符合规则";
    }else{ 
      msg.innerText = "用户名只能以数字、字母、下划线开头";
    }
  }
  
</script>

ps:input 元素是行级块元素,既可以设置宽高也不会占满一行,设置一下 .msg 元素 display: inline-block 就到一行了


用构造函数 RegExp() 的方式声明正则表达式,参数传的字符串是匹配规则

function checkedFun(str){
  var reg = new RegExp('^[\\da-zA-Z_]');
  // console.log(reg) 可以打印出定义的正则表达式
  if(reg.test(str)){
    msg.innerText = "符合规则";
  }else{ 
    msg.innerText = "用户名只能以数字、字母、下划线开头";
  }
}


 new RegExp('^[\\dA-z_]') 

参数是字符串,

在字符串中 \ 斜杠有特殊的含义,表示转义后面的一个字符,

要想实现 \d 的效果,要在加一个斜杠 \\d 转义一下,表示取消后面第二个 \ 斜杠的含义


reg.text(str)

正则表达式上的匹配方法

参数 str 是要校验的字符串,校验该字符串是否符合正则规则,返回一个布尔值


3、体验一些匹配规则

中括号与小括号的区别

(\da_)  小括号代表的是并列的关系有很项,匹配的字符样子先是数字、然后是字母a、后面是下划线(\da_ 不写小括号也可以)

[\da_]  中括号只有一项


$ 表示以什么结尾

/[\\da-zA-Z_]$/  以数字字母下划线结尾  

/[3578]$/   以 3578 中任意一个数字字符结尾都可以


量词 + 号代表 1 ~ 多个(* 代表 0 ~ 多个)

/[3578]+$/   匹配 3578 中任意一或多个数字字符结尾

/^[3578]+$/   以 3578 又以 3578 结尾,当字符串有一个不是 3578 的字符都是错误


/3578/   字符串中含一个这样 "3578" 的一个整体,不管 3578 出现在哪个位置


含有 s 的字符串

function hasLetterS(str) {
  return /s/.test(str);
}

console.log(hasLetterS("zzxsong")); // true
console.log(hasLetterS("zzxapple")); // false
console.log(hasLetterS("zzxSung")); // false(因为默认小写 s)
console.log(hasLetterS("zzxSung".toLowerCase())); // true(先转为小写)


二、原子表

什么是原子?

组成正则表达式的最小单位就是原子


方括号代表范围

语法说明
[abc]方括号内的任意一个字符
[^abc]^代表不在方括号内的字符,也就是不包含中括号里面的字符
[0-9]0-9 之间的数字
[a-z]任何小写字母
[A-Z]任何大写字母
[A-z]大写和小写字母
()子表达式
\uxxx查找十六进制数 xxxx 规定的 Unicode 字符
[\u4e00-\u9fa5]所有中文字符
参考图片连接


方括号跟小括号的区别

[ \dA-z_ ]   代表一个字符,方括号里面的内容是或的关系,任意一个字符可以是数字、可以是字母、可以是下划线

( \dA-z_ )   并列的关系,要匹配的,先是数字,后面是字母,最后是下划线(小括号也叫子表达式)


模式修饰符

修饰符说明
iignorecase 代表忽略大小写
mmultiline 代表多行匹配
gglobal  代表全局匹配,匹配出所有符合规则的子字符串(最常用)


示例

通过子表达式对整个 url 字符串各个部分,进行依次的匹配

var str = "https://www.baidu.com/s?tn=68018901_3_dg&ie=UTF-8&wd=flash";
var str = "https://www.bilibili.com/video/BV1qpCfY5Eaz/?spm_id_from=333.788.player.player_end_recommend_autoplay&vd_source=30698713e5e2b66f66e6fa017646273c#dsd";
var str = "http://127.0.0.1:8848/js%E6%96%B9%E6%B3%95%E6%95%B4%E7%90%86/text.html";

var reg = /(http|https):\/\/([\w\.]+)(:\d*)?(\/?[\w\/\.%-]*)\??([\w=\.&]+)?#?(.*)?/mig;

// console.log(reg.exec(str));

var arr = reg.exec(str);

var querys = {};

if(arr[5]){
  var _arr = arr[5].split("&");
  for(var i = 0; _arr.length > i; i++){
    var s = _arr[i].split("=");
    // console.log(s)
    querys[s[0]] = s[1];
  }
}

console.log(arr);

var obj = {
  protocol: arr[1],
  origin: arr[2], 
  port: arr[3], 
  path: arr[4], 
  query: querys
};

console.log(obj);


/(http|https):\/\/

协议以 http 或 https 开头

冒号后面的两个斜线 // 在正则表达式中有特殊含义,和正则表达式起始符 / 重复了,要用反 \ 斜线转义成字符串里面的斜线


/(http|https):\/\/([\w\.]+)/

域名规则是由多个字母、点、数字组成

\w 表示字母和数字

正则表达式里面“点”代表单个字符(除换行和行结束符以外的所有字符),也需要用反斜杠转义

+ 加号表示 1 至多个


/(http|https):\/\/([\w\.]+)(:\d+)?/

端口号由冒号和多个数字组成

\d+  加号的意思是 1 至多个数字

然后 ? 号是 0 次或 1次


/(http|https):\/\/([\w\.]+)(:\d*)?\/?([\w\/\.%-]*)/

abc.com/ 域名后面的斜线是路径,有时候默认不显示,所以可以出现 0 次

路径可能有英文字符、-、点、中文、斜杠、中文(中文部分转义后有 %)

路径是多个英文字符也可能没有,所以用 * 量词 0 次 1次 或 多次


/(http|https):\/\/([\w\.]+)(:\d*)?\/?([\w\/\.%-]*)\??([\w=&]+)?/mig

参数部分以 ? 号开头,? 号是正则里面的量词也需要转义 \?

? 号后面是参数,参数含有数字字母下划线、=、&

+ 参数可以是一到多个字符


使用 exec() 方法匹配返回的是类数组

[0]  是整个正则表达式匹配成功的内容

[1]  第一个子表达式匹配的内容

[2]  第二个子表达式

[3] ...... 从左往右数,如果有嵌套的小括号,从外往里依次的数


三、元字符

元字符列表

语法说明
.代表单个字符,除了换行符和行结束符以外的任意一个字符
\w小写 w 表示字母、数字、下划线,等价于 [A-Za-z0-9_]
\W非单词字符,就是除了小 \w 以外的字符
\d数字
\D非数字
\s空白字符
\S非空白字符
\b单词边界
\B非单词边界符
\n换行符
\f换页符
\r回车符
\t制表符
\v垂直字表符


. 点

正则表达式中“点”有特殊的含义,表示任意一个字符,

除了换行符和行结束符以外,其它的任意一个字符

换行符是 \n,行结束符就是回车 \r,也就是说 \n 和 \r 它都匹配不出来


 /.ello/g 

点 . 代表第一个字符

以任意一个字符开始,然后后面必须是 ello

修饰符 g 全局匹配,表示把所有符合条件的全部匹配出来

var str = "hello world, hello duyi, welcome duyi";

var reg = /.ello/g;

console.log(str.match(reg)); // ['hello', 'hello']


字符串的 match() 方法返回所有符合条件的“子字符串”是一个数组的形式

加了修饰符 g 返回的是数组

如果没有加 g 返回的是类数组,数组第一项 [0] 是第一个匹配到的字符串

var str = "hello world, hello duyi, welcome duyi";

var reg = /.ello/;

console.log(str.match(reg)); // ['hello', index: 0, input: 'hello world, hello duyi, welcome duyi', groups: undefined]

[

  0: "hello" 匹配成功的字符片段

  groups: undefined  groups代表一个组,这个组代表一个子表达式,没有子表达式就是 undefined

  index: 0 当前匹配成功的索引值

  input: "hello world, hello duyi, welcome duyi" 我们要匹配的整个字符串

  length: 1

]


点 . 不能匹配换行符 \n 和结束符 \r,可以匹配出制表符 \t

var str = "第一行 \nello world, \rello duyi, \tello lizi";

var reg = /.ello/g;

console.log(str.match(reg)); // ['\tello']


alert(str) 弹框里面可以看到换行符、回车符可以分行,制表符是一个空白

第一行

ello world, 

ello duyi, ello lizi


\w

小写 w 代表 26 个大小写英文的字母、数字、下划线

单纯的一个 \w

1. 返回了所有的英文字符

2. 但不包括空格、制表符、换行符、行结束符,逗号

var str = "\rello world, \nello duyi, \tello lizi";

var reg = /\w/g;

console.log(str.match(reg)); // ['e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd', 'e', 'l', 'l', 'o', 'd', 'u', 'y', 'i', 'e', 'l', 'l', 'o', 'l', 'i', 'z', 'i']


不要字符串里面的逗号、空格、制表符,就想要拆分出单词怎么办呢?

可以通过元字符和量词结合的方法,

量词就是元字符的个数,比如 + 加号表示匹配前一个字符的 1 至 多个字符


 \w+ 

元字符 \w 结合量词 +,返回的是字符串中一个一个的单词,去掉了逗号、空格、制表符

var str = "hello world, hello duyi, welcome duyi \tello";

var reg = /\w+/g;

console.log(str.match(reg)); // ['hello', 'world', 'hello', 'duyi', 'welcome', 'duyi', 'ello']


正则表达式的规则,一般都会遵循“贪婪匹配”

就是越多越好,所以量词 + 号是有几个就匹配几个,不是返回单个的字母了


 \w* 

* 星号代表 0 至 多个,也就是说没有的也能给匹配出来,

匹配出好多个空位,空就代表 0 个英文字符、还有空逗号、制表符都匹配成空位了

var str = "hello world, hello duyi, welcome duyi \tello";

var reg = /\w*/g;

console.log(str.match(reg)); // ['hello', '', 'world', '', '', 'hello', '', 'duyi', '', '', 'welcome', '', 'duyi', '', '', 'ello', '']


\W

大写 W 代表非单词字符,匹配所有的空格、逗号、制表符(就是除了字母、数字、下划线以外的

var str = "\rello world, \nello \tduyi";

var reg = /\W/g;

console.log(str.match(reg)); // ['\r', ' ', ',', ' ', '\n', ' ', '\t']

0: "\r"

1: " "

2: ","

3: " "

4: "\n"

5: " "

6: "\t"


\d

小写 d 代表数字,每一个数字一个一个的都匹配出来了

var str = "hello world123, hello456 duyi, welcome duyi \tello132323";

var reg = /\d/g;

console.log(str.match(reg)); // ['1', '2', '3', '4', '5', '6', '1', '3', '2', '3', '2', '3']


配合量词 + 号,匹配出连着的数字

var str = "hello world123, hello456 duyi, welcome duyi \tello132323";

var reg = /\d+/g;

console.log(str.match(reg)); // ['123', '456', '132323']


\D

大写 D 代表非数字,配合量词 + 号,除数字以外的其他字符都匹配出来了

var str = "hello world123, hello456 duyi, welcome duyi \tello132323";

var reg = /\D+/g;

console.log(str.match(reg)); // ['hello world', ', hello', ' duyi, welcome duyi \tello']

相当于数字充当了分割符

0: "hello world"

1: ", hello"

2: " duyi, welcome duyi \tello"


\s

小写 \s 表示空白字符,包含 \r、\n、\t

var str = "hello world\r, hello duyi, \nwel comeduyi\t";

var reg = /\s/g;

console.log(str.match(reg)); // [' ', '\r', ' ', ' ', ' ', '\n', ' ', '\t']
console.log(str.match(reg).length); // 8


\S

大写 S 非空白字符,匹配出没有 \r、\n、\t

var str = "hello world, hello duyi,\r welcome \nduyi \tello132323";

var reg = /\S+/g;

console.log(str.match(reg)); //  ['hello', 'world,', 'hello', 'duyi,', 'welcome', 'duyi', 'ello132323']


\b

匹配单词边界每一个单词有两个边界,七个单词有14个空白

var str = "hello world, hello duyi,\r welcome \nduyi \tello";

var reg = /\b/g;

console.log(str.match(reg)); // ['', '', '', '', '', '', '', '', '', '', '', '', '', '']


单词边界和空格的区别

1. 空格是有字符的,空白字符

2. 边界不是空格,整个字符如果连着 -hello- 左右两边是单词边界,也就是说一个单词有两个边界


\B

非单词边界就是两个挨着的字母之间

var str = "hello world";

var reg = /\B/g;

console.log(str.match(reg)); // ['', '', '', '', '', '', '', '']


非单词边界就是 h-e-l-l-o 字母之间

var str = "hello";

var reg = /\b/g;
console.log(str.replace(reg, '-')); // -hello-

var reg = /\B/g;
console.log(str.replace(reg, '-')); // h-e-l-l-o


非单词边界有什么用?

详看面试题“给 10000000000 每三个 0 打一个点变成 10.000.000.000”


先写 \d{3} 代表三个连续的数字 \d\d\d

我们要匹配的不是数字,匹配的是“非单词边界”,这个边界有一个特点后面跟着的是三个数字 000


边界后面跟着三个数字 -000 怎么表示呢?

量词里面有一个“正向预查”?=n

1. ?=n 是要加上括号的 (?=n)

2. m(?=n)  匹配后面紧跟着 n 的 m,意思是后面的 n 是条件,最后匹配出的是前面的 m

3. 后面的 n 是三个数字,前面的 m 是非单词边界,把 \B 加上就是我们要匹配的是非单词边界

打印出 8 个匹配到的位置

var str = "10000000000";

var reg = /\B(?=\d{3})/g;

console.log(str.match(reg, ".")); // (8) ['', '', '', '', '', '', '', '']


用 replace() 方法替换一下匹配成功的位置,发现有点不对

var str = "10000000000";

var reg = /\B(?=\d{3})/g;

console.log(str.replace(reg, ".")); // 1.0.0.0.0.0.0.0.000

为什么不对呢?

1.0000000000 第一个非单词边界的位置,后面跟着三个数字,替换一个点

1.0.000000000 第二个非单词边界的位置,后面跟着三个数字,替换一个点

1.0.0.00000000 第三个非单词边界的位置,后面跟着三个数字,替换一个点

1.0.0.0.0000000 依次类推

1.0.0.0.0.000000

1.0.0.0.0.0.00000

1.0.0.0.0.0.0.0000

1.0.0.0.0.0.0.0.000


我们需要结果是从后往前计数,每三位打一个点

需要在后面加 $ 符号表示从后往前

现在我们匹配的是以三个数字结尾的单词边界 10000000.000

var str = "10000000000";

var reg = /\B(?=\d{3}$)/g;

console.log(str.replace(reg, ".")); // 10000000.000


想再往前面接着每三个数字打一个点,就是3的倍数6

{3} 是量词,+号也是量词,

所以前面的 \d{3} 要加一个小括号和 + 隔开

var str = "10000000000";

var reg = /\B(?=(\d{3})+$)/g;

console.log(str.replace(reg, ".")); // 10.000.000.000


注意

问号后面是 等于=、大于>、小于< 的时候都需要扩上括号

(?=)  

(?>) 

(?<) 

只有问号在量词后面的时候,不需要加括号,因为它代表非贪婪匹配(至少匹配)

+?


四、量词

量词是修饰前面一个字符的个数,就是你想匹配多少个,下面的都遵循贪婪匹配

量词说明
n+1次多次
n*0次1次多次
n?0次1次
n{x}一个字符表白固定的个数
n{x,y}代表一个范围
n{x,}

n$匹配以n结尾的字符串
^n任何以n开头的字符串
?=n正向肯定预查m(?=n)  匹配任何后面紧接着指定字符串 n 的字符串
?!n正向否定预查m(?!n)  匹配后面不是 n 的 m
?<=n反向肯定预查(?<=n)m 匹配前面是 n 的 m
?<!n反向否定预查(?<!n)m 匹配前面不是 n 的 m
n+?n*?...
补充
(?:n)匹配时子表达式中没有这一项(不捕获分组)


上面用到的量词 + 号和 * 号,

都是至多匹配,有多少就拿多少,也就是贪婪匹配的原则


?

问号是至少匹配,只匹配 0 或 1 个,可以取消贪婪匹配


把英文字母一个一个的拿出来,只取字母不要空格

1. 全局 g 匹配,把全部符合的字符全都匹配出来

2. [A-z] 包括大小写字母

3. 字符串的 match 方法返回一个数组

var str = "hello world";

var reg = /[A-z]/g;

console.log(str.match(reg)); // ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd']


+

加上量词 + 号表示 1 次至多次,可以匹配出字符串中的两个单词,

这是正则的贪婪匹配的效果,至多就是能匹配多就不匹配少,有多少符合条件的字符都匹配出来作为一个字符串

var str = "hello world";

var reg = /[A-z]+/g;

console.log(str.match(reg)); // ['hello', 'world']


在加上 ? 问号,

表示至少匹配,是最少能拿几个就取几个作为一项(非贪婪匹配能少就不多),匹配结果又是一个一个的字母了

var str = "hello world";

var reg = /[A-z]+?/g;

console.log(str.match(reg)); // ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd']


{}

花括号里面只传一个数字,表示的是固定的个数,比如 3 个3个的进行匹配

var str = "hello world";

var reg = /[A-z]{3}/g;

console.log(str.match(reg)); // ['hel', 'wor']


2 个字符 2 个字符的进行匹配

var str = "hello world";

var reg = /[A-z]{2}/g;

console.log(str.match(reg)); // ['he', 'll', 'wo', 'rl']


如果花括号里面写两个数字,表示的是一个范围,

比如   { 2,4 }   范围是 2 ~ 4 个之间,贪婪匹配原则有多就不匹配少,4个4个的匹配出来

var str = "hello world";

var reg = /[A-z]{2,4}/g;

console.log(str.match(reg)); // ['hell', 'worl']


注意,

两个数字  { 2,   4 }  之间是逗号隔开,并且不能有空格

var str = "hello world";

var reg = /[A-z]{2, 4}/g;

console.log(str.match(reg)); // null


把中间有空格的  {2, 4}  放到字符里面

1. 之间的空格,就把空格当字符了

2. 中间就是空格的字符,不是一个范围了

var str = "hello world{2, 4}"; // 把{2, 4}写到这

var reg = /[A-z]{2, 4}/g;

console.log(str.match(reg)); // ['d{2, 4}']


[^A-z]

^ 在方括号里面不代表以某个字符开头了,代表除了中扩号以内的其他字符

var str = "hello world{2, 4}";

var reg = /[^A-z]/g;

console.log(str.match(reg)); // [' ', '{', '2', ',', ' ', '4', '}']


?=

m(?=n)  正向肯定预查,匹配后面紧跟着 n 的字符 m

详看“给 10000000000 每三个 0 打一个点变成 10.000.000.000


?!

正向否定预查,就是后面不跟着某一个字符(它用的不是很多),

1. a(?!d)  我们想匹配的是 a,但条件是 a 后面不能是 d

2. 修饰符 g 全局匹配出所有的

3. 字符串里面有三个 a,匹配出后面两个 a

var str = "adkhfalskdfa";

var reg = /a(?!d)/g;

console.log(str.match(reg)); // ['a', 'a']


?<=

反向肯定预查

(?<=f)a  我们想匹配 a ,条件是前面是 f 后面的那个 a

var str = "adkhfalskdfa";

var reg = /(?<=f)a/g;

console.log(str.match(reg)); // ['a', 'a']


?<!

反向否定预查

(?<!f)a  匹配的是 a,但是 a 的前面不能是 f,所以只有第一个 a 满足条件

var str = "adkhfalskdfa";

var reg = /(?<!f)a/g;

console.log(str.match(reg)); // ['a']


注意一个点

不管是那种预查,必须要加上小括号括起来,但是一定要与子表达式区分开

1. 因为我们知道,通过小括号括起来的就是子表达式

2. 预查这里比较特殊,小括号里面是预查的,它就不代表子表达式了


课堂提问

 /m(?<!f)a/g 

先找到前面的字符 m

m 后面的 (?<!f)a,a 的特点是前面不跟着 f

也就是 m 后面不是 f,然后在后面是 a,

它 (?<!f) 不是匹配的项,预查只是特点

该课堂的提问有点陷进预查里了,这样写没有什么意义,直接写 /ma/g 就可以了


五、子表达式

通过小括号括起来的就是子表达式,

子表达式有很多功能,需要我们去探索


1、反向引用

提取出三个相同连续重复的字符,比如 aaa、bbb、eee

/\w{3}/ 相当于 /(\w\w\w)/,每个 \w 有自己的范围,它的范围是字母、数字、下划线其中任意的一个字符,最后一个 dde 不符合要求

var str = "aaabbbddeee";

var reg = /\w{3}/g;

console.log(str.match(reg)); // ['aaa', 'bbb', 'dde']


什么是子表达式?

整个正则是一个大表达式,大表达式里面有很多的部分,我们想拿去一部分就用括号括起来,

子表达式可以拿到正则表达式中的一部分单独匹配,并将匹配成功的结果在整个正则表示中重复引用


 (\w)\1 

\1  是反向引用

数字 1 是子表达式的编号,代表引用第一个子表达式匹配出来的内容,

就是把子表达式匹配的内容拿出来用,所以匹配的内容跟第一个表达式相同

var str = "aaabbbddeee";

var reg = /(\w)\1/g;

console.log(str.match(reg)); // ['aa', 'bb', 'dd', 'ee']


 (\w)\1\1 

匹配三个相同的字符,就写两个 \1\1 反向引用

第一个字符是第一个子表达式 (\w)

这两个 \1\1 都是第一个子表达式里面匹配成功的字符

var str = "aaabbbddeee";

var reg = /(\w)\1\1/g;

console.log(str.match(reg)); // ['aaa', 'bbb', 'eee']


2、反向引用在字符串替换方法 replace() 里面的应用

字符串 replace() 替换方法

1. 第一个参数传是正则表达式 reg,会把满足正则的位置的字符进行替换

2. 如果参数二传递的是固定的字符串,会把符合匹配规则的部分进行替换

var str = "aaabbbddeee";

var reg = /(\w)\1\1/g;

console.log(str.replace(reg, '*')); // **dd*


replace() 方法的第二个参数还可以传一个回调函数

1. 该函数可以接收一些参数,通过打印 arguments 看到函数的形参

2. 函数 return 返回的内容是匹配成功的字符,就是把匹配成功的替换成什么的内容

var str = "aaabbbddeee";

var reg = /(\w)\1\1/g;

str.replace(reg, function(){
  console.log(arguments);
});

// 因为匹配成功三次,所以打印了三次,每一次打印的是一个数组
// Arguments(4) ['aaa', 'a', 0, 'aaabbbddeee', callee: ƒ, Symbol(Symbol.iterator): ƒ]
// Arguments(4) ['bbb', 'b', 3, 'aaabbbddeee', callee: ƒ, Symbol(Symbol.iterator): ƒ]
// Arguments(4) ['eee', 'e', 8, 'aaabbbddeee', callee: ƒ, Symbol(Symbol.iterator): ƒ]

[

  0: aaa, 是整个字符串匹配成功的字符

  1: a, 第一个子表达式 (\w) 匹配成功的内容

  2: 0, 是一个索引值,当前匹配成功的位置

]


传三个形参,并分别打印出来

var str = "aaabbbddeee";

var reg = /(\w)\1\1/g;

str.replace(reg, function(param1, param2, param3){
  console.log(param1, param2, param3);
});

// aaa a 0
// bbb b 3
// eee e 8


3、replace() 方法做字符串去重

  /(\w)\1+/ 

(\w) 先匹配一个字母,\1 第二个字母和子表达式匹配的相同,+ 然后可能有很多个这样的字母,只要重复的都匹配出来了

var str = "Aaadddoooooooobbeee";

var reg = /(\w)\1+/gi;

console.log(str.match(reg)); // ['Aaa', 'ddd', 'oooooooo', 'bb', 'eee']


接下来就替换重复的字符

回调函数里面 return 的内容,就是替换的内容,

意思是第二个参数 param2 是子表达式 (\w) 匹配成功的内容,它就一个字符,直接返回第二个参数 param2 就可以了

var str = "Aaadddoooooooobbeee";

var reg = /(\w)\1+/gi;

var result = str.replace(reg, function(param1, param2, param3){
  return param2;
});

console.log(result); // Adobe

去掉修饰符 i 就可以区分大小写了 Aadobe


课堂提问,

如果是两个 /1,替换重复 3 次的字符,

比如中间 8 个字母 o,三个三个的 ooo 被替换后变成两个 o,加上剩下的两个 o,所以结果是四个 o

var str = "Aaadddoooooooobbeee";

var reg = /(\w)\1\1/gi;

var result = str.replace(reg, function(param1, param2, param3){
  return param2;
});

console.log(result); // Adoooobbe


4、replace() 方法替换,高亮显示

做一个搜索关键词高亮显示效果,

原理就是给第一个参数 param1 加一个高亮样式后返回

正则表达式拼接关键词后是一个字符串,用 RegExp 方式的参数传的是字符串,所以用它定义正则表达式

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>搜索关键词高亮</title>
<style>
</style>
</head>
<body>

<script>
 
var str = '<span style="color:#999">快乐的池塘里面,有一只小青蛙,跳啊跳啊跳</span>';

var pond = '池塘';
var frog = '小青蛙'
var jump = '跳';

var keywords = `(${pond}|${frog}|${jump})`;

var reg = new RegExp(keywords, 'g');

var result = str.replace(reg, function(param1, param2, param3){
  return `<span style="color:#008c8c">${param1}</span>`;
});

document.body.innerHTML = result;

</script>
</body>
</html>


六、面试题

1. 正则表达式实现aabb的形式变成bbaaa

2. 给 10000000000 每三个 0 打一个点变成 10.000.000.000

3. 字符串去重 aaaaaaabbbbcccc 变成 abc

4. 把 the-first-name 转换成小驼峰 theFirstName

5. 匹配结尾的数字

6. 统一空格

7. 判断字符串是不是由数字构成

8. 删除字符串中的空格

9. 身份证号匹配

10. 将字符串

"select student.*, result.* from student inner join result on student.id = result.studentid"

和"select * from student"

中的 student 替换成 key 值


面试题 6. 统一空格

去掉多余的空格

var str = "Regexp    remove    string spaces";

var reg = /( )+/g;

console.log(str.replace(reg, ' ')); // Regexp remove string spaces


面试题 4. 把 the-first-name 转换成小驼峰 theFirstName

var str = "the-first-name";

// var reg = /(?<=-)\w/gi;
var reg = /-\w/gi;

var result = str.replace(reg, function(a, b, c){
  // console.log(a, b, c);
  return str[b+1].toUpperCase();
});

console.log(result); // theFirstName



Leave a comment 0 Comments.

Leave a Reply

换一张