正则表达式入门
完整的正则表达式由两种字符构成。特殊字符称为“元字符”,其他称为“文字”或者是普通文本字符。
为了便于理解,我们可以把正则表达式想象为普通的语言,普通字符对应普通语言中的单词,而元字符对应语法。根据语言的规则,按照语法把单词组合起来,就会得到能传达思想的文本。
| 特殊字符 | 正则表达式 | 记忆方式 |
|---|---|---|
| 换行符 | \n | new line |
| 换页符 | \f | form feed |
| 回车符 | \r | return |
| 空白符 | \s | space |
| 制表符 | \t | tab |
| 垂直制表符 | \v | vertical tab |
| 回退符 | [\b] | backspace,之所以使用[]符号是避免和\b重复 |
| 匹配区间 | 正则表达式 | 记忆方式 |
|---|---|---|
| 除了换行符之外的任意字符 | . | 句号,除了句子结束符 |
| 单个数字,[0-9] | \d | digit |
| 除了[0-9] | \D | not digit |
| 包括下划线在内的单个字符,[A-Za-z0-9_] | \w | word |
| 非单字字符 | \W | not word |
| 匹配空白字符,包括空格、制表符、换页符和换行符 | \s | space |
| 匹配非空白字符 | \S | not space |
| 匹配一个词的边界 | \b | boundary |
| 匹配一个非单词边界 | \B | not boundary |
\b和\B例子:
/\bm/匹配“moon”中的‘m’;
/oo\b/并不匹配"moon"中的’oo’,因为’oo’被一个“字”字符’n’紧跟着。
/oon\b/匹配"moon"中的’oon’,因为’oon’是这个字符串的结束部分。这样他没有被一个“字”字符紧跟着。
/\w\b\w/将不能匹配任何字符串,因为在一个单词中间的字符永远也不可能同时满足没有“字”字符跟随和有“字”字符跟随两种情况。
/\Boo/匹配"noonday"中的’oo’, 而/y\B/匹配"possibly yesterday"中的’yes‘。
最容易理解的脱字符号 ^ 和美元符号 $。
正则表达式cat寻找的是一行文本中任意位置的cat。但是^cat只寻找行首的cat——^用来把匹配文本“锚定”在这一行的开头。同样,cat$只寻找位于行末的cat。
脱字符号^和美元符号$的特别之处在于,它们匹配的是一个位置,而不是具体的文本。
字符组
如果我们需要搜索的单词是grey,同时又不确定它是否写作“gray”,就可以使用正则表达式结构体[...]。它允许使用者列出在某处期望匹配的字符,通常被称作字符组。 gr[ea]y的意思是:先找到g,跟着是一个r,然后是一个a或者e,最后是一个y。
例如123456匹配1到6中的任意一个数字。这个字符组可以作为H[123456]的一部分,用来匹配<H1>到<H6>。在搜索html代码时很有用。
在字符组内部,字符组元字符 - 表示一个范围:H[1-6]和H[123456]是完全一样的。0-9和a-z常用作匹配数字和小写字母的简便方法。多重范围也是允许的,例如[0123456789abcdefABCDEF]可以写作[0-9a-fA-F],可用于处理十六进制数字。
⚠️:只有在字符组内部,连字符才是元字符。否则它就只能匹配普通的连字符号。 其实,即使在字符组内部,它也不一定就是元字符。如果 连字符 出现在字符组放入开头,它表示的就是一个普通字符,而不是一个范围。同样的道理,问号也通常被当作元字符处理,但在字符组中则不是如此。例如[0-9A-Z_!?]里面,真正的特殊字符只有那两个连字符。
小发现:
/[ads]/.test() // true
看到这里我觉得很奇怪了,为啥这里test结果为true?
我们再看另一个?:
var reg = /[ads]/;
reg.exec()
// 这里我们得到一个数组
// ["d", index: 2, input: "undefined", groups: undefined]
从这个例子可以发现如果没有制定匹配内容,会匹配undefined这个字符串,导致匹配了内容。如果我们是这样的:/[aaa]/.test()得到的结果就会是false了。
排除性字符组
用 [^…]取代[…],这个字符组就会匹配任何未列出的字符。
例如,[^1-6]匹配除了1到6以外的任何字符。 这个字符组中开头的^表示 排除,所以这里列出的不是希望匹配的字符,而是不希望匹配的字符。
再看另一个例子,要匹配一对单词中字母q后面不是u的单词:q[^u]。
用点号匹配任意字符
元字符.是用来匹配任意字符的字符组的简便写法。
如果需要匹配06/17/52、06-17-52或者06.17.52,可以用03[-./]19[-./]76来匹配。若需要匹配间隔为任意字符的,可以用03.19.76来匹配。
在这里要注意的是,在03[-./]19[-./]76中,点号.并不是元字符(⚠️在字符组里面和外面,元字符的定义和意义是不同的)。这里的连字符-同样也不是元字符,因为它们紧贴在[或者[^之后。如果连字符不在字符组的开头,例如[.-/],这个就是用来表示范围的。
匹配任意子表达式
| 的意思是或。我们回头来看看gr[ea]y的例子,还能写作grey|gray或者gr(e|a)y。注意gr[e|a]y不符合要求,因为在字符组中,|只是一个和e和a一样的普通字符。
一个字符组只能匹配目标文本中的单个字符,而每个多选结构自身都可能是完整的正则表达式,都可以匹配任意长度的文本。
字符组基本可以算是一门独立的微型语言,而多选结构是“正则表达式语言主体”的一部分。
忽略大小写
-i表示进行忽略大小写的匹配
总结:
-
在字符组内部,元字符的定义规则是不一样的。比如说,在字符组外部,点号是元字符,但在内部就是普通字符;脱字符
^在字符组外部是匹配文本“锚定”在这一行的开头,在字符组内部紧接着[时会匹配任何未列出的字符,在其他情况是普通字符。 -
不要混淆多选项和字符组
-
排除型字符组是表示所有未列出字符的字符组的简便方法。
[^x]的意思并不是“只有当这个位置不是x时才能匹配”,而是说“匹配一个不等于x的字符”。例如,前面的概念可以匹配一个空行,而^x则不行。
可选项元素
我们来看看 color 和 colour 的匹配。我们可以用colou?r来解决这个问题。
元字符?代表可选项。把它加在一个字符的后面,就表示此处容许出现这个字符,不过它的出现并非匹配成功的必要条件,即匹配前面的子表达式零次或一次。
重新出现
+和*的作用与?类似。元字符+表示之前紧邻的元素出现一次或多次,而*表示之前紧邻的元素出现任意多次,或者不出现。+、*和?这三个元字符,统称为量词,因为它们限定了所作用元素的匹配次数。
与?一样,正则表达式中的*也是永远不会匹配失败的,区别只在于它们的匹配结果(*是贪婪匹配,?是非贪婪匹配)。
规定重现次数的范围:区间
使用元字符序列来自定义重现次数的区间:…[min,max]。这称为区间量词。
变量名
标识符只能包含字母、数字以及下划线,但不能以数字开头。我们可以用[a-zA-Z_][a-zA-Z_0-9]*来匹配标识符。如果标识符的长度有限制,例如最多只能是32个字符,我们可以用到区间量词{min,max},即用{0,31}来替代最后的*。
引号内的字符串
匹配引号内的字符串可用“[^“]*”。
var reg = /“[^“]*”/;
reg.exec('引号外面的内容“引号里面的内容”bulabula');
// ["“引号里面的内容”", index: 7, input: "引号外面的内容“引号里面的内容”bulabula", groups: undefined]
表示时刻的文字
例如“9:17am”或“12:30pm”
[0-9]?[0-9]:[0-9][0-9](am|pm)
能匹配到“9:17am”和“12:30pm”,但也能匹配无意义的时刻,如99:99*pm。
如果小时数是一个两位数,第一位只能是1。但是1?[0-9]仍然能匹配到19,所以更好的办法应该把小时部分分为两部分处理。1[012]匹配两位数,1-9匹配一位数,结果就是(1[012]|[1-9])。
我们再来看分钟数。第一位数字应该是[0-5],第二位数字应该是[0-9]。综合起来就是(1[012]|[1-9]:[0-5][0-9](am|pm))。
举一反三:24小时制的写法:
(([01]?[0-9])|(2[0-3])):[0-5][0-9]
接下来我们测试下:
var reg = /(([01]?[0-9])|(2[0-3])):[0-5][0-9]/;
reg.test('20:23') // true
reg.test('25:23') // true

怎么肥事???25:23也可以?
不急,我们再看下:
reg.exec('25:23')
// ["5:23", "5", "5", undefined, index: 1, input: "25:23", groups: undefined]
这里是匹配到了5:23.然后我想了下,改成了这样:
var reg = /(([01]+[0-9])|(2[0-3])):[0-5][0-9]/;
现在是可以的了。但是有一个缺陷,我也想匹配9:13这样的,即前面的0是可选的,这样就不支持了。
为了支持让它全部匹配,我又改成了这样:
var reg = /((^[01]?[0-9])|(^2[0-3])):[0-5][0-9]/;
这样就是可以的了。
子表达式
子表达式指的是整个正则中的一部分,通常是括号内的表达式,或者是括号内的表达式,或者是由|分隔的多选分支。
例如,在[^(subject|date):]中,subject|date通常被视为一个子表达式,其中的subject和date也算得上子表达式。严格来说,s、u、b这些字符,都算子表达式。
本文深入浅出地讲解了正则表达式的概念与应用,包括元字符、字符组、量词、子表达式等核心内容,通过实例帮助读者掌握正则表达式的使用技巧。
1311

被折叠的 条评论
为什么被折叠?



