ziishaned/learn-regex: Learn regex the easy way
- 学习正则表达式需要注意,正则只列举语法没用,一定要把具体使用列出来。
- characters 字符
- 多行修饰符
- "quantifiers 量词(重复次数):*, +, ?, {}"
#- `*` * 0n
#- `+` + 1n
#- `?` ? 01 表示可以不出现,比如`an?`可以匹配到`a`和`an`
#- `{}运算符` 用来限定一个或一组字符可以重复出现的次数 `be{2}r` 用来匹配 beer `be{3,}r`表示至少出现 3 次 {m,n} 出现 m 到 n 次
- groups 分组
- white-space 空白符(其他项):\f, \n, \r, \t, \v
#- . 任意字符(换行除外)
#- \f 换页符
#- \n 换行符
#- \r 回车符
#- \t 制表符
#- \v 垂直制表符
- character classes 字符类:
- 特殊单字符(简写字符集):\d, \D, \w, \W, \s, \S
#- \d 数字[0-9]
#- \D 非数字
#- \w 字母数字下划线[a-zA-Z0-9_]
#- \W 非字符数字下划线
#- \s 所有空格字符串[\t\n\f\r\p{Z}]
#- \S 匹配除了空格以外的字符
- anchors and boundaries 锚点和边界
- inline modifiers 内联修饰符
- "***模式修正符:(忽略大小写i (?i), 全局搜索g, 多行匹配m, 惰性匹配(在量词后加上 ? 将使得相关匹配项变成惰性模式, 正则默认贪婪匹配), 具名捕获)***"
#- `忽略大小写i` ignore
#- `全局搜索g` global
#- `多行修饰符m` multiline
#- `贪婪匹配(默认)`和`惰性匹配?` 正则默认贪婪匹配,用`.*?r`惰性匹配出`ber beer beeer`中的`ber`
#- 独占模式
- 忽略大小写:如果用正则匹配,实现部分区分大小写,另一部分不区分大小写,这该如何操作呢?就比如说我现在想要,the cat 中的 the 不区分大小写,cat 区分大小写。
# //
# // ((?i)the) cat
# // the cat
# // The cat
# // THE cat
# // thE cat
#
# // (?i)cat
# // cat CAT caT
- 多行匹配:m 标志位代表多行匹配,^和$将用于匹配任意行的开头和结尾,而不再是整个字符串的开头和结尾。
# '1\n2\n3'.match(/^\d+$/g)
# // null
# '1\n2\n3'.match(/^\d+$/mg)
# // ["1", "2", "3"]
- 惰性模式:在量词后加上 ? 将使得相关匹配项变成非贪婪模式,在非贪婪模式下匹配将尽可能匹配短内容,这会返回更多匹配项:
# '12345'.match(/\d+/g)
# // ["12345"]
# '12345'.match(/\d+?/g)
# // ["1", "2", "3", "4", "5"]
- 具名捕获
- "***特殊运算符:`锚点、转义运算符\ 、或运算符|、点运算符、特征标群(...)`***"
# 锚点
#- `^号`: 开头,插入符,表示开始匹配字符串,只匹配行首
#- `$号`: 结尾,结束符,只匹配(该字符串)行尾的字符
# 范围
#- `转义运算符\` 匹配`特殊字符{ } [ ] / \ + * . $ ^ | ?`时,用来转义这些特殊字符
#- `或运算符|` 表示或者(比如用`(\*|\.)`匹配`(*) Asterisk.`中的`*`和`.`)
#- `点运算符.` 匹配任意*单个字符*,但不匹配换行符
#- `特征标群(...)` () 被视为一个整体 `(?:):非捕获分组`
#- `be[^ou]r` 不能是括号中的任意单个字符,反选匹配出`bear beor beer beur`中的
- 非获取匹配 (non-capturing) (?:):非获取匹配是获取匹配的反面,在使用括号 () 的情况下,非获取匹配并不会作为匹配项返回(也不能用于后向引用),非获取匹配通常是为了使一个由多个字符组成的匹配项能够加上量词,却又不希望该匹配项会作为捕获的结果返回。
# '1234'.match(/^(\d)(\d)(\d)(\d)$/)
# // ["1234", "1", "2", "3", "4"]
# '1234'.match(/^(?:\d)(?:\d)(?:\d)(?:\d)$/)
# // ["1234"]
# '1234'.match(/^(?:\d)(\d)(\d)(?:\d)$/)
# // ["1234", "2", "3"]
# '1234'.match(/^(\d)(?:\d){2}(\d)$/)
# // ["1234", "1", "4"]
- 分组引用
- back-references 反向引用:
- "***lookarounds 断言(零宽度断言):正向断言 `(?=)`, 正向否定断言 `(?!)`, 反向断言 `(?<=)`, 反向否定断言 `(?<!)`***"
#- `正向先行断言?= 存在` 比如用`\d+(?=PM)`匹配出`Date: 4 Aug 3PM`中的`3`
#- `负向先行断言?! 排除` 用`(?<=\$)\d+`匹配出`Product Code: 1064 Price: $5`中的`5`
#- `正向后发断言?<= 存在` 用`(?<!\$)\d+`匹配出上面的`1064`
#- `负向后发断言?<! 排除`
- flags 标志位
- unicode(比如 emoji, 汉字)
# emoji /\p{Emoji}/u
# 汉字 `/\p{Han}/u` 等价于 `/\p{Script=Han}/u`
- 常用regex
# - \\D只保留数字
# - \s.* 以空格开始的所有字符
# - [u4e00-\u9fa5] 选择所有汉字
# - [^\u4e00-\u9fa5]^[-,.?:;'\"!'] 选择所有非汉字,但是不包括-,.?:;'"!'这些标点符号
# - ^((?!abc).)*admin((?!abc).)*$ 包含 admin 且不包含 abc。
- 给正则添加注释
# // 正则还可以通过 (?#xxx) 的形式添加注释
# // (\w+)(?#word) \1(?#word repeat again)
- regex中,怎么不保存子组