正则表达式
前言
一直以来都逃避正则,但写代码不会一点正则有时候真的很痛苦,所以还是得学一下最基本的. 这里做一下笔记呗.
参考:
匹配
\b
如果我们想匹配一个单词. 比如 hi, 那么我们一定不希望它匹配到 his, hit 等等
那么我们可以加上 \bhi\b 这样就 ok 了. 它的逻辑是匹配的字前后不可以是字母或数字 (符号, 空格都是 ok 的)
.
点匹配万物, 除了换行
\d
匹配数字, 小数点不匹配哦,不要傻傻的
\w
匹配字母,数字, 汉字和下划线, 不要问我为什么跑出一个下划线来...
如果不希望下划线,也可以用另一个写法 [a-zA-Z0-9] 但这个不匹配汉字
\s
匹配空格和 tab
^ 和 $
通常会一起用, ^ 是表示匹配第一个字符串开始. 比如 ^a 就是说第一个字一定要是 a
如果只是 a 那么意思是字符串里头只要有 a 就可以了, ^ 就只能是开头就要 a
$ 就是结尾.
所以我们验证一整个字符串通常就会用到这个了
匹配数量
上面讲了匹配,接下来讲一下要求匹配的数量
*
0次或多次, 比如 aaa 如果我只是写 a 那么会有 3 给 match (每一个 match 里面一个字)
而我写 a* 就只有一个 match 里面有 3 个字
+
1次或多次. 和 * 一样, 唯一区别是 * 可以 0 次,这个最少一次
?
0次或1次, 就是有或没有. 重点不是数量了, 所以它是没有多次概念的
{n}
n 就是任你写一个数字. 要配个几个就几个
{n,}
n 个以上, 反过来是没有的哦 {,n} 《--这个是错误的
{n,m}
inclusive between n and m
其它
方括号[]
方括号是单个匹配,如[abc]他限制的不是abc连续出现,而是只能是其中一个,这样写那么规则就是找到这个位置时只能是a或是b或是c;
方括号是正则表达式中最常用的,常用的用法有:[a-zA-Z0-9]匹配所有英文字母和数字,[^a-zA-Z0-9]匹配所有非英文字母和数字。
这段抄来的. 我还没悟道, 之后再写.
里面不是连环的,而是类似单个 or , 比如 [aeiou] 匹配的不是连续而是 a 或 e 或 i 或 o 或 u.
另一个特点是 [.] 匹配的是 . 而不是任意字符, 但是 [\s] 依然是匹配空格. 所以不能理解为里面没有元字符. 再研究
|
或者 \d{3} | abc 就是说 3 个数字或者匹配 abc 字符串
反义 not
\S \s 以外
\W \w 以外,
\D \d 以外
[^aeiou] 加上 ^ 表示以外
[^a-zA-Z0-9_\s] 可以算是匹配符号
(\d)
圆括弧是把表达式抱起来用,和数学有点像.
然后就是这样写 (ab){2} ab出现 2次, 如果是 ab{2} 那么只是 b 出现 2 次.
(ab|cd) 配合 or 也是经常的用法
断言
参考: 正则表达式分组、断言详解
<title>dada</title>
如果想匹配出 dada 而已, 那么就一定要用到断言了.
断言的功能是它可以写一些匹配,但是最终缺没有被匹配出来
像上面的表达是这样的
我想找 .* whatever 但是前面必须是 <title> 后面必须是 </title>
4 种断言写法
(?=X)
(?<=X)
(?!X)
(?<!X)
共同点是 (?)
然后一种是等于(=), 一种是不等于(!)
然后一种有箭头(<), 一种没有. 有箭头的是说断言放在前面. 没有的就放后面
所以上面的写法是
step 1 : *. 匹配所有
step 2 : (?<=<title>).* 断言在前面所有要箭头
step 3: (?<=<title>).*(?=<\/title>) 断言在后面所以没有箭头
Javascript 正则
题目: 找出 href 值
const html = ` <a href="/contact">Contact</a> <a href="/about">About</a>`;
答案 /contact 和 /about
创建 regex
const regex = new RegExp('<a .*href="(.*)"', 'img');
第一个参数是 pattern, 它是一个 string, 可以动态拼接哦.
第二个参数 'gim' 分别代表
global: 是否要匹配多个, 还是只匹配出第一个.
ignoreCase : 匹配不区分大小写
multiline: 当有多行 (\n) 的时候 ^$ 开头结尾是每一行.
如果没有要动态拼接, 也可以用 regex syntax, 下面这句和上面是等价的
const regex = /<a .*href="(.*)"/gim;
查看 regex
console.log(regex.ignoreCase); // true console.log(regex.multiline); // true console.log(regex.global); // true console.log('source', regex.source); // <a .*href="(.*)"
这些都是 readonly 属性哦, 无法修改的. 只能重新做新的
执行查找
console.log(regex.exec(html));
console.log(regex.exec(html));
console.log(regex.exec(html));
结果
两个点要注意:
1. 执行了 3 次, 但是 result 是不同的哦. Regex 内部会记入执行到哪里, 下一次继续, 直到最后匹配不到返回 null, 然后再从头开始.
2. 返回的 array 第一个是完整匹配, 第二个是圆括弧的局部匹配. 如果有多个圆括弧, 那么 array 会有第 3,4,5... 个
Regex.test
console.log(regex.test(html)); // true
它是一个简单的匹配返回 boolean, 匹配到就返回 true, 没有就返回 false.
String.match and String.replace
上面都是用 Regex 去做匹配, 它比较底层, 虽然可以实现所以需求, 但是不过方便.
string.match, replace 则是它的上层封装.
console.log(html.match(regex));
console.log(html.replace(regex, 'value=$1'));
结果
两个点要注意:
1. match 无视圆括弧, 它只返回完整匹配到的
2. replace 可以内可以使用 $1 表示第一个圆括弧匹配的值. 它适合用在当想替换所有字但是其中一小部分要保留的时候.
C# 正则
var html = @" <a href=""/contact"">Contact</a> <a href=""/about"">About</a> "; var regex = new Regex(@"<a .*href=""(.*)""", RegexOptions.IgnoreCase | RegexOptions.Multiline); var matchCollection = regex.Matches(html); foreach (var matched in matchCollection.ToArray()) { var childMatched = matched.Groups[1].Value; }
和 JS 大同小异, 我只说说不同的地方.
1. C# 没有 Global, 它是在调用的时候通过 regex.Match 和 regex.Matches (plural 作为 Global) 来表达的, .Replace 则一定是 Global
2. match Collection 结构比较多层, 但是依然可以拿到圆括弧的匹配
replace
var value = regex.Replace(@"<a .*href=""(.*)""", "value=$1");