likes
comments
collection
share

记一个正则问题的解决

作者站长头像
站长
· 阅读数 8

记一个正则问题的解决

问题:

'iphone /**\n * 绩效标签[xxxx/ / ipad /* xxxx/ / ipadmini /* xxxx* / mac /* xxx/x */ macpro' 获取字符串中的'iphone', 'ipad', 'ipadmini', 'mac', 'macpro'

思路: 用split方法,将类似于js注释的部分/** xxx /给去掉 正则描述前面是/**,后面是/,中间是非*/的字符

const reg = //**[^(*/)]**// 代码:

const Apple = 'iphone /**\\n * 绩效标签[xxxx/ */ ipad /** xxxx/ */ ipadmini /** xxxx* */ mac /** xxx/x */ macpro';
const reg = /\/\*\*[^(\*\/)]*\*\//;
console.log(Apple.split(reg));

测试结果: [ 'iphone /**\n * 绩效标签[xxxx/ / ipad /* xxxx/ / ipadmini /* xxxx* / mac /* xxx/x / macpro' ] 并不是我们想要的结果,说明[^(*/)]并不是非/的意思,可以做一个验证

测试代码:

const str = 'mm)ff(ccc/aaa*bb*/'
const reg = /[^(\*\/)]+/g;
console.log(str.match(reg));

结果: [ 'mm', 'ff', 'ccc', 'aaa', 'bb' ]

可以看出来在正则中括号中是没有分组的概念的,里面的字符都是字符本身

非*/的方式不能解决需要采用直接匹配的方式,改为非/的字符或者是/但前面不能是*(也可以是非*的字符或者是*但后面不是/),这里需要用到后行否定断言

const reg = //**([^/]|(?<!*)/)+*//

测试代码:

const Apple = 'iphone /**\\n * 绩效标签[xxxx/ */ ipad /** xxxx/ */ ipadmini /** xxxx* */ mac /** xxx/x */ macpro';
const reg = /\/\*\*([^/]|(?<!\*)\/)+\*\//g
console.log(Apple.split(reg));

结果: ['iphone ', ' ', ' ipad ', ' ', ' ipadmini ', ' ', ' mac ', ' ', ' macpro']

可以看出来split结果中每两个结果之间多了一个,查看split的文档发现,如果正则中包含分组会将分组的结果展示出来,具体说明

如果 separator 包含捕获括号(capturing parentheses),则其匹配结果将会包含在返回的数组中。

var myString = "Hello 1 word. Sentence number 2.";
var splits = myString.split(/(\d)/);
console.log(splits);

上例输出: [ "Hello ", "1", " word. Sentence number ", "2", "." ]

所以将分组改为不捕获的分组(?:)

const reg = //**(?:[^/]|(?<!*)/)+*//

测试代码

const Apple = 'iphone /**\\n * 绩效标签[xxxx/ */ ipad /** xxxx/ */ ipadmini /** xxxx* */ mac /** xxx/x */ macpro';
const reg = /\/\*\*(?:[^/]|(?<!\*)\/)+\*\//g
console.log(Apple.split(reg));

结果

[ 'iphone ', ' ipad ', ' ipadmini ', ' mac ', ' macpro' ]

最后加上空格匹配

const reg = /\s*/**(?:[^/]|(?<!*)/)+*/\s*/

总结

  1. 正则中,中括号中没有分组的概念,字符就是字符本身
  2. 掌握先行和后行断言 x(?=y) x(?!y) (?<=y)x (?<!y)x
  3. split中正则分组的使用
  4. 正则中分组不捕获 (?:exp)

先行和后行断言说明

1. x(?=y) 先行断言

x 被 y 跟随时匹配 x。例如,对于/Jack(?=Sprat)/,“Jack”在跟有“Sprat”的情况下才会得到匹配./Jack(?=Sprat|Frost)/ “Jack”后跟有“Sprat”或“Frost”的情况下才会得到匹配。不过, 匹配结果不包括“Sprat”或“Frost”。

2. x(?!y) 先行否定断言

x 没有被 y 紧随时匹配 x。例如,对于/\d+(?!.)/,数字后没有跟随小数点的情况下才会得到匹配。对于/\d+(?!.)/.exec(3.141),匹配‘141’而不是‘3’。

3. (?<=y)x 后行断言

x 跟随 y 的情况下匹配 x。例如,对于/(?<=Jack)Sprat/,“Sprat”紧随“Jack”时才会得到匹配。对于/(?<=Jack|Tom)Sprat,“Sprat”在紧随“Jack”或“Tom”的情况下才会得到匹配。不过,匹配结果中不包括“Jack”或“Tom”。

4. (?<!y)x 后行否定断言

x 不跟随 y 时匹配 x。例如,对于/(?<!-)\d+/,数字不紧随 - 符号的情况下才会得到匹配。对于/(?<!-)\d+/.exec(3) ,“3”得到匹配。 而/(?<!-)\d+/.exec(-3)的结果无匹配,这是由于数字之前有 - 符号。