Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

巩固一下js的正则表达式 #5

Open
sevenCon opened this issue Jul 24, 2019 · 0 comments
Open

巩固一下js的正则表达式 #5

sevenCon opened this issue Jul 24, 2019 · 0 comments

Comments

@sevenCon
Copy link
Owner

sevenCon commented Jul 24, 2019

前言

js正则表达式, 平时用的倒是挺多, 但是就是缺少系统的学习, 感觉没有一次可以脱离文档的. 当看到一些源码里面一些前瞻,后顾的运用的时候,常常觉得梦里似曾相识, 对面相逢却不认得.

正文

我常会把search, match, 混淆到正则对象的方法里面, 和exec, test相提并论,
造成这种的尴尬的原因也很简单, 就是里面包含了正则表达式.

但是search, match的理解和记忆本来就和String字符串挂钩, 搜索字符, 和匹配子字符串.

String.search() 直接返回子串匹配的索引

let idx = `
123haha`.search(/ha/);  // => 3
idx = '123haha'.search(/ha/g);  // => 3

全局匹配和非全局并没有什么不同

String.match() 返回null, 或者匹配的结果数组

// global
let ret = '123haha'.match(/haha/);  
// => ['haha'] 

// not in global
'123haha'.match(/haha/)
// => ["haha", index: 3, input: "123haha", groups: undefined]

需要注意的是, match的参数的一定是正则, 没有字符串类型的参数, 不像search, replace, split等等.

返回的直接就是匹配的数组或者null.
分2种情况.

  • g,代表全局匹配, 那么返回就是一个null, 或者数组, 数组中的元素是每个匹配成功的子字符串, 如上.
  • 没有g,代表全局匹配, 返回也是一个null, 或者数组, 但是数组的元素是匹配的字符串和子分组的字符串的组合. 这个数组还有一个属性, index,表示匹配的下标, input, 表示原字符串, 另外还有一个不支持的groups, 表示具名分组的内容. 具名分组在V8里面早已经实现了regexp-named-groups

至于上面有2个haha, 则是因为第二个是分组的子串.

let ret = '123haha'.match(/(?<haha>haha)/)
console.log(ret);
// ["haha","haha", index: 3, input: "123haha", groups: {haha:'haha'}]

具名分组的方式, 也是用来反向引用, /(?<haha>haha)\k<haha>/,
和String相关的正则方法一些字符串还有replace,split

String.replace() 返回替换后的字符串

replace的参数有2个, 第一个是匹配替换的字符串/正则, 第二个是替换匹配的字符串/函数

主要是第二个参数, 在函数的情况下, 参数的个数是不定.

let ret = '123haha'.replace(/(?<haha>haha)/g, function(){ console.log(arguments) });

//  => ["haha"            /* 匹配的字符串 */, 
//      "haha"            /* 匹配的子字符串 */, 
//      3                 /* 匹配的字符索引下标 */, 
//      "123haha"         /* 原字符串 */, 
//      {haha: "haha"},   /* 具名分组 */]

和match的非全局匹配的情况是是一致的, 只是数据格式会不一样, 这里的匹配的索引, 和原匹配的字符串, 都是放到了数组里面吗, 如果有具名匹配的话, 还会把具名匹配的对象放到最后一个参数后,

注意的是, 具名分组只有chrome支持.

RegExp.exec() 检索字符串的匹配

let reg = /ha/;
let gReg = /ha/g;

let arr = reg.exec('123haha');
// => ['ha', 3, '123haha']
// reg.lastIndex => 0, 永远是0


let arr = gReg.exec('123haha');
//=> ["ha", index: 3, input: "123haha", groups: undefined]
//gReg.lastIndex => 5

arr = gReg.exec('123haha');
//=> ["ha", index: 5, input: "123haha", groups: undefined]
//gReg.lastIndex => 7

arr = gReg.exec('123haha');
//=> null
//gReg.lastIndex => 0

exec和match一样, 也是区分全局匹配, 和非全局匹配的.

  • 在有g, 全局匹配下, 那么会修改lastIndex的值, 作为改正则下一次进行exec()调用的起始下标.
    全局匹配的情况下,lastIndex记录下一次开始匹配的下标, 依次返回数组, 匹配为空则为null, lastIndex为0, 证明完成匹配.
  • 没有g, 非全局匹配下, 进行的匹配和match非全局匹配是一致的, 返回的是一个由匹配字符串, 分组字符串, 匹配的下标, 原匹配字符串, 具名分组信息, 组成的数组;

在这里呢, 就有个疑问? lastIndex是否只有exec才能用? 可以通过手动修改lastIndex, 开始特定位置的匹配位置吗?

是否可以通过lastIndex, 编辑匹配的起始位置?

// RegExp.test
let reg = /\d/g;
reg.lastIndex = 1;

let testStr = '1';
reg.test(testStr) // => false;
// 结论: test 会检查和按照lastIndex来进行其实的匹配


testStr.match(reg) // => ['1'];
testStr.search(reg) // => 0
testStr.replace(reg, 'match') // =>'match';
// 结论: match,search,replace  不会检查和按照lastIndex来进行其实的匹配

结论: test, exec 可以通过编辑RegExp.lastIndex, 来定义其实的匹配开始位置, 而这个对String的方法来说不起作用.

正则的相关规则

说道这里, 正则的相关内容很多,

符号 含义
(?:x) 非捕获分组, 可以和(), 配套记忆
x(?=y) 前瞻断言
x(?!y) 前瞻否定
(?<=y)x 后顾,
[^xyz] ^的第二个作用, 否定, 需要和[]配合使用
\b 单词边界, 如good boy, 这个间隙不是单词间空格,-good- -boy-, - 就是\b
\B 非单词边界, 即是上述的单词边界的除外.
\w 0-9a-zA-Z_
\W 0-9a-zA-Z_以外的字符
\d 0-9
\D 0-9 以外的字符
\t 制表符tab
\f 分页符
\v 垂直制表符\v后面的字符从下一行开始输出,且开始的列数为“\v”前一个字符所在列后面一列
\s 空格,包括空白字符,包括空格、制表符、换页符和换行符
\S 非空格,空白字符,包括空格、制表符、换页符和换行符
\n 反向引用 比如 /apple(,)\sorange\1/匹配apple, orange, cherry, peach.中的apple, orange,

举个例子

'123\v456'
//=> 会是以下这样
123
   456

需要注意的是, 上述除了() 捕获分组之外, 前瞻,后顾,都是不捕获分组的.

金额3位一组, 添加,显示

'12345678'.replace(/\B(?=(\d{3})+$)/g,',');
// => 12,345,678

电子邮箱

/^\w+@\w+.([a-z]+)$/g.test(1111@qq.com);

结尾

  • exec, match区分全局匹配, 非全局匹配, 非全局匹配会有input, index属性
  • replace, 区分第二个参数是否是函数, 如果是函数参数则是匹配串, 分组子串, 下标, 原字符串, 具名分组

replace, split, search, match

https://segmentfault.com/a/1190000015208294
本文的github地址为 巩固一下js的正则表达式, 如侵权或其他问题, 请issue留言, 感谢!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant