分类
js

JavaScript 获取正则表达式中子表达式的个数

正如标题所示,我厂有这么一个需求。我不会,老板鄙视我后丢过来一个链接:stackoverflow: Count the capture groups in a qr regex?

看不太懂 Perl,但是这个思路很棒。所以改写成 JS 版,并记录如下:

function countCapturingGroups(r){
  r = new RegExp(`|${r.source}`);
  const result = ''.match(r);
  return result.length - 1;
}

const result = countCapturingGroups(/fo(.)b(..)/);
console.log(result); // 2

它的原理是这样的。构建一个新正则,包含两部分:空字符和目标正则。空字符正则会完成与目标字符串的匹配,保证有结果(不然的话就会返回 null。接下来 | 会保证后面的正则也是有效的,可以生成包含子表达式结果的数组。

我们知道,结果是个类数组,结构大约是:

  1. 全部匹配字符串
  2. 0~N 子表达式结果
  3. 其它一些属性

所以用其长度 – 1 就能获得子表达式的个数。从功耗上来说,这个应该是很节省了。

分类
技术

正则笔记

常看常新的正则教程

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

匹配中文及中文标点

const reg = /[\u4E00-\u9FCC\u3002\uff1b\uff0c\uff1a\u201c\u201d\uff08\uff09\u3001\uff1f\u300a\u300b]+/g

ES2018~ES2019 中的正则

分类
js

记一个正则问题

前几天写代码,遇到一个需求:

  1. 解析 sleep NUMBER 这样的命令
  2. 能够识别缺参数或者参数错误的情况

这个正则并不复杂,初步写出来大概是这样:sleep\s+(.*)。这样,$1 就是参数,然后就可以检验。但是 .* 匹配“任意字符出现零次或多次”,所以实际测试发现它根本不匹配任何参数。

然后我就改成了 sleep(?:\s+(.*))?,然后在下一步 trim。这样,sleep 后面整个都是可选参数,就能解决上面的问题。

然后就被老板骂了……老板的答案是 sleep\s+(.*?)\s*$。重点在于后面的 $,要求正则必须匹配行尾,这样一来,懒惰模式的 .*? 就需要一直匹配到行尾,并且尽量少匹配内容,所以诸如 a b 之类的情况也可以正常跑匹配了。


从这里,我学到:

  1. $\b 虽然并不能匹配到一个确定的字符,但它们同样意义重大
  2. 不特定长度匹配,包括 *+,甚至 {n, m},在懒惰模式下,后面都要尽量跟上明确的结束条件,以便让前面尽快结束。
分类
js 技术

给URL加上合理的“/”收尾

Astinus 0.2版升级过程中,有一个Feature是这样的:

小雷的数据源只能识别如“http://www.zol.com.cn/”的请求,前面必须有http,后面必须有“/”。我的目标是无论用户输入什么,都能得到正确的结果。

开始想的比较简单,直接就这么写了

function correctURL (str) {
  var tail = url.substr(url.lastIndexOf('/') + 1);
  if (tail.indexOf('?') == -1 && tail.charAt(tail.length - 1) != '/') {
    url += '/';
  }
  return url;
}

写这段代码时已过午夜,脑子比较糊涂,次日中午反应过来,赶紧修改,经过反复调试,得到正确结果:

function correctURL(str) {
  var tail = url.substr(url.lastIndexOf('/') + 1);
  if (tail != '' && tail.match(/\.(s?html?|php|asp)/) == null && tail.charAt(tail.length - 1) != '/') {
    url += '/';
  }
  return url;
}

顺便说下,Chrome的JavaScript控制台在调试时真好用。另外,将来也要考虑采用测试驱动的方法来写JS了。