让你成为正则表达式大师的完整指南
这是正则表达式系列文章的第二篇。在第一篇文章中,您可以了解正则表达式的常见用例。本文通过示例和速查表,讲解了日常使用正则表达式所需的一切知识。之后的一篇文章将讲解正则表达式最高级的用例,这些用例将充分发挥正则表达式的真正威力,但这些用例很少被使用。
在本文中
- 像我五岁一样解释正则表达式
- 正则表达式的语法是什么?
- 最常见的正则表达式标志
- 正则表达式的开始和结束
- 常规字符(文字字符)
- 特殊字符(元字符)
- 多个特殊字符
- 正则表达式中的常规字符列表
- 正则表达式中的特殊字符列表
- 特殊代币
- 量词 - 字符重复
- 角色类别
- 负面字符类
- 将字符类与量词结合起来
- 正则表达式组 101 - 或运算符
- 贪婪修饰符
- 成为正则表达式大师
像我五岁一样解释正则表达式
Regex(或正则表达式)是一种在文本中搜索和匹配模式的语言,使用特殊字符来描述要查找或替换的字符类型或字符序列。
关于正则表达式,最基本的理解是当你不输入任何特殊字符或使用任何正则表达式语言特有的功能时,它是如何工作的。在这种情况下,如果文本中存在相应的字符,正则表达式中的每个字符都会匹配文本中的相应字符,就像在常规文本搜索字段中一样。
在上图中,我们可以看到正则表达式在字符串/all/中使用标志g和m找到的精确匹配。它在字符串中总共找到了六个匹配项。
请注意,正则表达式仅用于查找这六个匹配项。我们想如何处理这些匹配项则取决于我们自己。常见的做法是将匹配的字符替换为其他字符。在其他情况下,我们只需要知道文本是否与正则表达式匹配,例如,为了检测用户输入的电子邮件地址是否有效。要了解更多关于正则表达式的用途,请阅读本系列的上一篇文章。
正则表达式的语法是什么?
正则表达式通常定义在两个正斜杠之间,后面跟着几个字母。
// Common syntax for a regex.
/someregex/ig
斜线仅定义我们正在编写的是一个正则表达式,而尾随的字母称为标志,可以改变正则表达式的解释方式。
在某些语言中,我们可以使用其他方式定义正则表达式。例如,在 JavaScript 中,可以使用RegExp构造函数。
// In JavaScript you can define a regex with a regex constructor.
const myRegex = new RegExp('someregex', 'i');
// Above is the same as defining a regex with the standard slashes syntax.
const myRegex = /someregex/i;
在 UI 中,例如 IDE 中的搜索字段,通常可以通过启用正则表达式按钮来允许使用正则表达式。这样做时,通常无需输入正则表达式周围的斜杠,并且有时可以编辑标志,但并非总是如此。
您可以使用带有 .* 图标的按钮在 VS Code 搜索字段中激活正则表达式
在继续解释标志之前,需要注意一点。您需要注意,不同编程语言的实现中,正则表达式的语法可能略有不同。它们对正则表达式的解释并不完全相同,但大多数都很好地遵循了标准。
最常见的正则表达式标志
正则表达式有很多标志。并非所有语言和编辑器都支持所有标志。因此,我在这里只介绍最常用、通常都受支持的标志。
i和g旗使用最为频繁。s和m旗也有可能用到,但不一定。
标记:i
正则表达式标志i是最容易理解的标志。它的作用是使正则表达式解释时不区分大小写。这意味着无论您输入什么,正则表达式都会匹配大写和小写字母。如果不指定此标志,正则表达式将区分大小写。
// This regex will not find a match in the string "Regex explained",
// since "Regex explained" has a capital R in it.
/regex explained/
// When using the i flag, this regex will match "Regex explained" string.
/regex explained/i
标志:g
另一个非常常见的标志是g标志,是g global的缩写。该标志告诉正则表达式解释器查找正则表达式的所有匹配项,而不是只查找第一个匹配项(即使没有该标志,解释器也会查找第一个匹配项)。最好用一张图片来解释!
g 标志告诉正则表达式引擎查找所有可能的匹配,而不仅仅是第一个
这里棘手的部分可能不在于理解 g 标志的作用,而在于它何时重要。如果你使用正则表达式仅测试文本是否与某个模式匹配,例如检查文本是否包含你的名字,那么 g 标志实际上并不重要。无论你找到你的名字一次、两次还是一千次,答案都是它包含你的名字。唯一的区别是,正则表达式引擎必须更加努力才能找到所有一千次出现的地方。
如果您将正则表达式用于其他目的,例如替换文本中某个单词的所有出现,那么 g 标志就是您想要的,否则您只会替换该单词的第一次出现!
const text = 'What is regex? What can you do with regex?';
// Without the g flag, regex engine will only replace the first match of the regex.
console.log(text.replace(/regex/, 'love'));
// Output: What is love? What can you do with regex?
// With g flag, regex engine will replace all matches of the regex.
console.log(text.replace(/regex/g, 'love'));
// Output: What is love? What can you do with love?
标志:s
s代表单行。它实际上意味着即使正则表达式包含换行符,也会被视为单行。通常,正则表达式不会搜索多行匹配项。在正则表达式语言中,它的意思是,点正则表达式字符(表示任何字符)可以匹配换行符 (\n)。
在上面的例子中,正则表达式的.*部分表示任意数量的字符。本文稍后会对此进行更详细的解释。目前,只需理解 s 标志允许正则表达式跨越多行即可。
旗帜:m
m标志代表m多行。搞混了吗?我们上面讨论单行的时候不是已经解释过了吗?别担心,没必要举白旗。
s标志影响正则表达式中点字符的解释方式,而m标志则影响起始和结束字符 ^ 和 $ 的处理方式。现在我们继续讨论它们,m 标志将在那里进一步解释。
正则表达式的开始和结束
编写一个正则表达式来确保字符串以特定字符开头和/或结尾是一个非常常见的用例。正则表达式语言使用脱字符 ( ^ ) 表示字符串的开头,使用美元符号 ( $ ) 表示字符串的结尾。
通常,正则表达式的开头和结尾表示正则表达式搜索的整个字符串的开头和结尾,而与字符串的行数无关。字符m改变了插入符号和美元符号的含义,使它们代表正则表达式中每一行的开头和结尾。实际上,这意味着搜索字符串中的每个换行符 ( \n ) 都将被视为一行的结尾,同时也是新行的开头。
m 标志改变了插入符号 (^) 的含义,使其匹配行首而不是整个字符串的开头
请注意,我们不能总是期望插入符号和美元符号匹配字符串的起始和结束。这或许就是正则表达式如此复杂的原因,因为它会根据周围的字符改变字符的含义。让我们稍微讨论一下这一点,以阐明正则表达式中哪些字符是正常的,以及所有特殊字符的作用。
常规字符(文字字符)
替代名称:常规字符、文字字符
标志、特殊字符、点和插入符号(它们的含义会随着标志的变化而改变)……正则表达式中没有常规字符吗?是的!有!它们被称为文字字符,您可以安全地使用这些字符,而不必担心它们会被以奇怪的方式处理。
- 字母:az,大写和小写
- 数字:所有数字,0 至 9
是啊,就是这样...毕竟没有那么多。
开个玩笑,字符真的太多了!比如@、&和%。其实大多数字符都是普通字符。更容易理解的是,哪些字符在正则表达式中具有特殊含义,然后假设其他所有字符都是普通字符。
特殊字符(元字符)
替代名称:特殊字符、元字符
正则表达式语法包含许多特殊字符,正则表达式引擎会使用这些字符来理解正则表达式。这些字符被称为元字符。元字符是指对计算机程序、解释器(或本文中指正则表达式引擎)具有特殊含义的字符的统称。
特殊字符的一个例子是加号 ( + ),它表示前面的字符可以出现一次或多次(参见量词部分)。如果希望正则表达式将特殊字符解释为字符字面值本身,则需要使用反斜杠 ( \ ) 对其进行转义。
// The + character means that the character before it should exist at least once.
Regex /bun+y/ will match string "buny".
Regex /bun+y/ will match string "bunny".
Regex /bun+y/ will match string "bunnny".
Regex /bun+y/ will NOT match string "buy", because one n is required by the + sign.
Regex /bun+y/ will NOT match string "bu+y", because the plus character is treated as a metacharacter.
// If you want to match a + sign, you will need to escape it with a backslash.
Regex /bun\+y/ will match string "bun+y".
简而言之,特殊字符是指在正则表达式中需要将其视为字符本身时需要进行转义的字符。如果不进行转义,特殊字符将成为正则表达式语法的一部分,用于向正则表达式引擎描述如何解释该正则表达式。
我们很快就会看到正则表达式中特殊字符的完整列表,但在此之前,我们应该看看我所说的多重特殊字符。
多个特殊字符
替代名称:特殊字符、元字符
说实话,“多用途特殊字符”并不是一个正式的术语,只是我现在在编造。因为我需要一种方法来区分多用途特殊字符和单用途特殊字符。
正则表达式中令人困惑的地方在于,特殊字符并不总是特殊的。其他特殊字符始终是特殊的,但它们与其他特殊字符组合时含义会发生变化。这就是为什么我将这些特殊字符称为多重特殊字符,它们在正则表达式语法中扮演着多种角色。
幸运的是,多重特殊字符并不多。不过,有一个非常重要的字符,那就是连字符 ( - )。它通常被解释为普通连字符,但当连字符在字符类(方括号)中使用时,它会被视为定义字符范围的范围字符。
// A hyphen in a regex is normally treated as a hyphen literal.
Regex /a-d/i will match string "a-d".
Regex /a-d/i will NOT match the strings "a", "b", "c" or "d".
// Within square brackets, hyphen is treated as a range character.
Regex /[a-d]/i will NOT match strings "a", "-" or "d", because the hyphen is in a character class.
Regex /[a-d]/i will match the strings "a", "b", "c" and "d", because a-d is treated as a range of characters.
// If you want to match a hyphen in a character class, you need to escape it.
Regex /[a\-d]/i will match strings "a", "-" and "d", because hyphen is escaped.
// Meaning of square brackets is explained in detail in character classes section.
正如之前在讨论起始和结束字符时提到的,插入符号 ( ^ ) 在正则表达式中的含义也会发生变化。与连字符一样,它在方括号中的行为也有所不同。因此,它被称为负字符类,我们将在本文后面讨论。
现在回答一下,多个特殊字符会让您感到困惑吗?不用担心。您可以将它们视为任何其他特殊字符,唯一需要记住的是,某些特殊字符可以用于多种用途。
正则表达式中的常规字符列表
特点 | 评论 |
---|---|
信件 | 字母 az,包括大写和小写。 |
语言特定字母 | 通常支持并视为常规字符。 |
数字 | 所有数字都是常规字符。 |
& | “&”符号是正则表达式中的常规字符。 |
@ | 在正则表达式中,符号是一个常规字符。 |
, | 逗号是正则表达式中的常规字符。 |
# | 标签是正则表达式中的常规字符。 |
% | 百分号是正则表达式中的常规字符。 |
_(下划线) | 下划线是正则表达式中的常规字符。 |
由于常规字符数不胜数,此列表并不完整。如有疑问,请查看特殊字符列表,其中包含完整列表。
正则表达式中的特殊字符列表
本文详细介绍了每个特殊字符。此列表还引用了“前向循环”和“后向循环”这两个术语。它们用于高级用例,将在另一篇文章中解释。
特点 | 评论 |
---|---|
-(连字符) | 被视为连字符字面量,如果位于某个字符类中,则被视为范围字符。在字符类中使用时,需要进行转义才能被视为连字符。 |
= | 等号被视为常规字符,除非它用于定义前瞻或后瞻表达式(?=)或(?<=)。 |
! | 感叹号是常规字符,除非它用于定义负向前看或负向后看表达式(?!)或(?<!)。 |
? | 问号是可选字符的量词。当它跟在量词后面时,也可以用作贪婪修饰符,本文末尾将对此进行解释。最后,在前向循环和后向循环语法中,当它作为括号 (?!)、(?=,)、(?<=) 或 (?<!) 中的第一个字符时,可以使用问号。 |
{} | 用于量词的语法中,否则被视为常规花括号。 |
[] | 方括号是字符类的语法。 |
\ | 反斜杠用于转义字符或书写特殊符号,例如换行符 (\n)。如果需要匹配反斜杠符号,则需要使用另一个反斜杠对其进行转义。 |
+ | 加号是一个量词,表示前面的字符应该匹配一次或多次。 |
* | 星号是一个量词,表示前面的字符应该匹配零次或多次。 |
。 | 点字符用于匹配任何其他字符。除非与量词结合使用,否则仅匹配单个字符。除非使用 s 标志,否则它不匹配换行符。 |
管道 | 管道字符用作或运算符。 |
/ | 在编程语言中,斜杠 i 常用于括起正则表达式。如果要将其视为斜杠文字,则必须使用反斜杠进行转义。 |
“ | 双引号在正则表达式中被视为常规字符,但如果正则表达式是用双引号定义的字符串的一部分,则可能需要在编程语言中进行转义。 |
' | 单引号在正则表达式中被视为常规字符,但如果正则表达式是用单引号定义的字符串的一部分,则可能需要在编程语言中进行转义。 |
<> | 小于和大于字符将被视为常规字符,除非它们用于定义正向或负向后行表达式(?<=)或(?<!)。 |
^ | 插入符号用于定义字符串的开头。使用m标志时,它匹配以换行符 ( \n ) 分隔的每一行的开头。插入符号也用于负字符类[^]的语法中。 |
$ | 美元符号用于定义字符串的结尾。当使用m标志时,它匹配以换行符 ( \n ) 分隔的每一行的结尾,并将被视为行尾。 |
() | 括号用于定义字符组。 |
特殊代币
替代名称:特殊字符、元字符
当你在谷歌上搜索正则表达式时,你会发现每个网站上人们对某些事物的命名都不一样。因此,你可能把特殊标记简称为元字符、特殊字符或标记。在本文中,我将它们称为特殊标记,因为从语法上讲,它们与正则表达式中的其他特殊字符有所不同。
从语法上看,它们与其他特殊字符有点相反,因为特殊标记使用反斜杠转义字符(在其他正常字符文字前面)将其解释为特殊字符。
以下是特殊标记的列表。如您所见,大多数标记都可以用其他方式书写。此表并不完整。许多特殊标记由于很少使用或出现,因此此处已省略。
代币 | 描述 | 替代方案 |
---|---|---|
\d | 匹配单个数字 | [0-9],[0123456789] |
\D | 与 \d 相反。匹配任何非数字字符 | [^0-9],[^0123456789] |
\w | 匹配字母表中的任意字母、任意数字和下划线 | [a-zA-Z0-9_] |
\W | 与 \w 相反。匹配任何非数字、下划线或拉丁字母的字符 | [^a-zA-Z0-9_] |
\s | 匹配空白字符 | 常规空格字符通常有效,但请注意,也存在制表符、换行符和其他一些空白字符。 |
\S | 与 \s 相反。匹配除空格之外的任何字符 | 请参阅 \s 以了解更多信息。 |
\n | 匹配换行符 | |
\r | 匹配回车符 | |
\t | 匹配水平制表符 | |
\b | 匹配单词边界,即单词的开头或结尾。因此,正则表达式/\bex/匹配example中的ex,但不匹配regex中的ex。 | 有人可能认为空格字符 \s 与 \b 相同,但与 \b 不同,\s 在句子的开头或结尾不起作用,因为那里没有空格。 |
\B | 与 \b 相反。确保它不是单词的开头或结尾。 |
量词 - 字符重复
别名:出现指示符、重复运算符
通常,在正则表达式中输入一个字符时,正则表达式引擎只会匹配一个该字符。正则表达式语法中有一些特殊字符可以用来改变这种行为。这些特殊字符称为量词,总是直接放在它所影响的字符之后。
例如,问号表示前一个字符应该出现 0 次或 1 次,也就是说它是一个可选字符。问号可以用来表示美式拼写和英式拼写。
// The question mark quantifier can be used to match a character zero or one time.
Regex /colou?r/ will match the string "color".
Regex /colou?r/ will match the string "colour".
Regex /colou?r/ will NOT match the string "colouur".
所有其他量词都以相同的方式工作。它们要求前面的字符重复一定次数。
特点 | 描述 | 例子 | 匹配 | 无匹配 |
---|---|---|---|---|
? | 匹配前一个字符零次或一次 | 兔子? | 买,兔子 | 兔子 |
* | 匹配前一个字符零次或多次 | 兔子* | 买,兔子,兔子 | |
+ | 匹配前一个字符一次或多次 | 面包+y | 兔子,小兔子 | 买 |
{2} | 匹配前一个字符两次 | 兔子{2} | 兔子 | 买,兔子,兔子 |
{2,4} | 匹配前一个字符两到四次 | 兔子{2,4} | 兔子,兔子,兔子 | 买,兔子,兔子 |
{2,} | 匹配前一个字符两次或两次以上 | 兔子{2,} | 兔子,兔子,兔子,兔子 | 买,兔子 |
角色类别
替代名称:括号表达式
语法:[]
字符类是正则表达式中非常重要的一部分。它允许你声明一组要匹配的字符,而不是指定一个要匹配的精确字符。要使用它,请将所有替代字符写在方括号 ([]) 中。
// One and only one of the characters in a character group will be matched.
Regex /optimi[sz]ation/ will match both "optimization" and "optimisation".
Regex /optimi[sz]ation/ will NOT match "optimiation", because either s or z is required.
Regex /optimi[sz]ation/ will NOT match "optimiszation", because only one of s and z is allowed.
在上面的例子中,你可以看到,当定义了一个字符类时,正则表达式引擎只会接受该组中的一个字符。如果你想匹配多个字符,你可以将其与量词组合使用。
// Combine a character class with a quantifier if you want to accept more
// than one of the characters within the group to be matched.
Regex /m[isp]+/ will match "mississippi".
Regex /m[isp]+/ will match "miss".
Regex /m[isp]+/ will NOT match "sim", because m must be placed before i, s and p.
很多情况下,你可能想把很多字符放入一个字符类中。然而,声明所有字符可能很麻烦。在这种情况下,你可以在字符类中定义一个字符范围。范围的语法是两个字符之间用连字符连接,例如 az 和 0-9。
Regex /[a-z]/ will match any one character in the alphabet.
Regex /[a-z]/ will NOT match a number.
Regex /[a-z]/ will NOT match a whitespace character.
Regex /[a-z]+/ will match any characters in the alphabet, one or multiple (i.e. a word).
Regex /a[a-z]+/ will match any word starting with the letter a.
Regex /a[a-z]+a/ will match any word starting and ending with an a.
Regex /a[a-z]+a/ will NOT match "a hyena", because whitespace is not included in the character class.
Regex /a[a-z ]+a/ will match "a hyena", because whitespace is now included in the character class.
Regex /a[a-z\s]+a/ will match "a hyena", because \s represents a whitespace character.
您可以在字符组中定义任意数量的范围,只需根据需要添加它们即可。
Regex /[1-3]/ will match one of the integers 1, 2 and 3.
Regex /[1-36-9]/ will match one of the integers 1, 2, 3, 6, 7, 8, 9
Regex /[6-91-3]/ is the same as above, just a suspicious way to write it...
Regex /[1-36-9]/ will NOT match any of the integer 4, 5 or 6.
Regex /[a-z0-9] will match any lower-case letter or any integer.
Regex /[0-15-7A-Ceg]/ will match any of the characters 0, 1, 5, 6, 7, A, B, C e and g.
// Remember that regexes are case sensitive without the i flag?
Regex /[a-z]/ will match any lower case letter.
Regex /[A-Z]/ will match any upper case letter.
Regex /[a-zA-Z]/ will match any letter, upper or lower case.
Regex /[a-z]/i will match any letter, upper or lower case, because the i flag is specified.
现在,你还记得我们读过关于多重特殊字符的内容吗?这些字符既可以充当常规字符,又可以充当特殊字符。连字符就是其中之一。通常,它被视为普通字符,但在字符类中,它被用作范围语法。这也意味着,如果你想让字符类使用连字符来查找匹配项,你必须对其进行转义。
Regex /[a-c]+/ will match "aaa", "abc", "acb" and "cccccc".
Regex /[a-c]+/ will match NOT matchc "a-a", because it contains a hyphen.
Regex /[a\-c]+/ will match "a-a", "a-c", and "c-a", because the hyphen is escaped (and treated as a hyphen character).
Regex /[a\-c]+/ will NOT match "abc", because the hyphen is not a range character, so b is not included in the character class.
Regex /[a-c\-]+/ will match "a-a" and "abc", because we both have a regular hyphen and a range character in the character class.
Regex /a-[cd]/ will match "a-c" and "a-d", because a hyphen outside a character class is treated as a hyphen.
Regex /a-[cd]/ will NOT match "ac" or "ad", because the hyphen is required.
在编写正则表达式时,你会经常使用字符类。不过,大多数情况下,你会反复使用相同的字符类。az、AZ 和 0-9 范围在正则表达式中非常常见,尤其是在它们与量词组合以匹配任何单词或单词序列时。
Regex /[a-z]+/ will match any word, but no whitespaces.
Regex /[a-z\s]+/ will match multiple words.
Regex /the[a-z\s]+green/ will match any text that starts with "the" and ends with "green".
细心的读者可能已经注意到,在上面的一个例子中,我使用了特殊符号 \s 来代替字符组中的空格。你可以在字符类中正常使用特殊符号,就像在字符类之外使用它们一样。
Regex /a\scobra/ will match "a cobra".
Regex /a\scobra/ will NOT match "acobra", because the whitespace is required.
Regex /a[abcor\s]/ will match "a cobra".
Regex /a[abcor\s]/ will match "acobra", because the whitespace is not required.
负面字符类
替代名称:负括号表达式
语法:[^]
当你在字符类的开头写一个插入符号 (^) 时,它将被视为负字符类。负字符类与字符类相反。它们的工作方式与字符类相同,但不是声明哪些字符必须出现,而是定义哪些字符不能出现。
Regex /pineapple/ will match "pineapple".
Regex /pin[e]apple/ will match "pineapple".
Regex /pin[^e]apple/ will NOT match "pineapple", because the letter e is not allowed between n and a.
Regex /pin[^e]apple/ will match "pinkapple", because it is only the e between the n and a that is forbidden.
将字符类与量词结合起来
与常规字符文字和特殊标记一样,字符类只能替换单个字符,除非与量词结合。
Regex /[0-9]/ will match 3 or 8, but NOT 38.
Regex /[0-9][0-9]/ will match 38, but NOT 3 or 8.
Regex /[0-9]{2}/ will match 38, but NOT 3 or 8.
Regex /[0-9]{1-2}/ will match 38, 3 or 8.
Regex /[0-1][0-9]{2}/ will match a three digit number starting with 0 or 1.
Regex /0[1-9]{2}-[0-9]{7}/ will match a phone number on format 0XX-XXXXXXX.
Regex /[0-1]+/ will match any binary number.
正则表达式组 101 - 或运算符
组是正则表达式中最难理解的功能之一,在日常工作中很少用到。因此,我们将在本系列的下一篇文章中解释组。现在,我们将通过一个简单且非常常见的用例来满足您的需求,即在正则表达式中仅包含两个或多个单词中的一个。为此,我们使用或运算符,即管道符。
Regex /(a|b)c/ will match "ac" or "bc", but NOT "abc".
Regex /(a|b)c/ will NOT match "c", because a or b is required.
Regex /optimi(s|z)ation/ will match "optimisation" or "optimization".
Regex /(red|blue)/ will match "red" or "blue", but NOT "redblue" or "lue".
Regex /(red|blue) color/ will match "red color" or "blue color", but NOT " color".
贪婪修饰符
别名:贪婪量词、贪婪运算符
我们已经看到,问号符号可以用作量词,指定其前面的字符匹配零次或一次。问号在正则表达式中还有另一个重要用途,它也可以用作贪婪修饰符,使量词变得“懒惰”而不是“贪婪”。
通常,量词是贪婪的。这意味着它们会尝试匹配尽可能多的字符。如果在量词后添加贪婪修饰符,则该量词将匹配尽可能少的字符。
成为正则表达式大师
至此,我们几乎了解了所有关于正则表达式语法的知识。为了从正则表达式专家晋升为高手,我们还需要学习一些其他知识。这些内容将在下一篇文章中介绍。
如果你喜欢正则表达式和益智游戏,可以来我的网站上玩玩程序员益智游戏。要达到更高级的水平,你需要了解正则表达式!
文章来源:https://dev.to/perssondennis/complete-guide-to-make-you-a-regex-guru-3i1k