分组
| 表达式 | 描述 |
|---|---|
| (expression) | 分组。匹配括号里的整个表达式 |
| (?:expression) | 非捕获分组。匹配括号里的整个字符串但不获取匹配结果,拿不到分组引用。 |
我们先从正则表达式数量词说起,如果我们要求字符b至少出现一次,可以使用正则/b+/;如果要求ab至少出现一次,那么必需使用/(ab)+/,不能用/ab+/。
也就是说,如果想对多个字符使用数量词,必需要用圆括号。
const str = "a1***ab1cd2***c2";
const reg1 = /((ab)+\d+)((cd)+\d+)/i;
const reg2 = /((?:ab)+\d+)((?:cd)+\d+)/i;
console.log(str.match(reg1)); // ab1cd2,ab1,ab,cd2,cd
console.log(str.match(reg2)); // ab1cd2,ab1,cd2
可以看出捕获分组和非捕获分组的区别了吧:非捕获分组,只是用来匹配,并不会提取分组内容。也就是说,如果我们只想用圆括号将一些字符用数量词修饰,并不需要这个分组的内容,这就是非捕获分组。
下面这段代码用来提取sql语句中的各个子片段,大量使用了非捕获分组,可以细细品味下。
const sql = "select * from students where (name = 'a' or name = 'b');"
const returnfields = sql.match(/^\s*SELECT\s+((?:[0-9A-Za-z_]+\s*,\s*)+[0-9A-Za-z_]+ |\*|[0-9A-Za-z_]+)\s+FROM\s+([a-z0-9A-Z_]+)(?: where\s+\((.+)\))?(?:\s+order\s+by\s+([a-z0-9_A-Z]+)(?:\s+(asc|desc|ascnum|descnum)?))?(?:\s+limit\s+(\d+,\d+))?/i);
console.log('returnfields', returnfields)
const ops = {
fields: returnfields[1].replace(/\s/,'').split(','),
from: returnfields[2].replace(/\s/,''),
where: (returnfields[3] == undefined) ? "true" : returnfields[3],
orderby: (returnfields[4] == undefined) ? []: returnfields[4].replace(/\s/,'').split(','),
order: (returnfields[5] == undefined) ? "asc": returnfields[5],
limit: (returnfields[6] == undefined) ? [] : returnfields[6].replace(/\s/,'').split(',')
};
console.log('ops', ops)
// console.log('returnfields', returnfields)
1. 0: "select * from students where (name = 'a' or name = 'b')"
1. 1: "*"
1. 2: "students"
1. 3: "name = 'a' or name = 'b'"
1. 4: undefined
1. 5: undefined
1. 6: undefined
1. groups: undefined
1. index: 0
1. input: "select * from students where (name = 'a' or name = 'b');"
1. length: 7
// console.log('ops', ops)
1. fields: ['*']
1. from: "students"
1. limit: []
1. order: "asc"
1. orderby: []
1. where: "name = 'a' or name = 'b'"
关于这段正则有几个地方解释下:
1.字段名和表明只能由大小写字母、数字和下划线组成。
2.where后面的条件必须放在()中,否则不能匹配。这个和真正的SQL是不同的。
3.select后面的字段有3种格式:单个字段、多个字段(以逗号分隔)、所有字段(用*表示)。
4.where子语句、order by子语句、limit子语句都是可选的。
文字的力量是无穷的