网站敏感关键词.txt,seo薪资水平,成都logo标志设计,03173软件开发工具编程工具和技术是以一种混乱、进化的方式生存和传播的。获胜的并不总是最好或最杰出的工具#xff0c;而是那些在合适的利基市场中发挥足够好的功能#xff0c;或者恰好与另一项成功的技术相结合的工具。 在本章中#xff0c;我将讨论这样一种工具--正则表达式。正则表达式是… 编程工具和技术是以一种混乱、进化的方式生存和传播的。获胜的并不总是最好或最杰出的工具而是那些在合适的利基市场中发挥足够好的功能或者恰好与另一项成功的技术相结合的工具。 在本章中我将讨论这样一种工具--正则表达式。正则表达式是一种描述字符串数据模式的方法。正则表达式是一种描述字符串数据中模式的方法它是一种独立的小语言是 JavaScript 以及其他许多语言和系统的一部分。 正则表达式既非常笨拙又非常有用。它们的语法令人费解JavaScript 为它们提供的编程接口也很笨拙。但它们却是检查和处理字符串的强大工具。正确理解正则表达式将使你成为一名更高效的程序员。
创建正则表达式 正则表达式是一种对象类型。它既可以用 RegExp 构造函数构造也可以用正斜杠 (/) 字符将模式括起来写成文字值。 这两个正则表达式对象表示相同的模式一个 a 字符后接一个 b 字符后接一个 c 字符。
在使用 RegExp 构造函数时模式被写成普通字符串因此通常的规则适用于反斜线。
第二种符号即模式出现在斜线字符之间对反斜线的处理略有不同。首先由于正斜线会结束模式因此我们需要在希望成为模式一部分的正斜线前加上反斜线。此外不属于特殊字符代码如 \n的反斜线将被保留而不是像在字符串中那样被忽略从而改变模式的含义。某些字符如?和在正则表达式中具有特殊含义如果要表示字符本身则必须在其前面加上反斜线。 测试匹配度 正则表达式对象有许多方法。最简单的方法是测试。如果你向它传递一个字符串它将返回一个布尔值告诉你该字符串是否包含表达式中的匹配模式。 由非特殊字符组成的正则表达式只表示该字符序列。如果 abc 出现在我们要测试的字符串的任何位置而不仅仅是开头test 将返回 true。
字符集 调用 indexOf 也可以查出一个字符串是否包含 abc。正则表达式非常有用因为它允许我们描述更复杂的模式。 比方说我们想匹配任何数字。在正则表达式中将一组字符放在方括号中表达式的这一部分就会匹配方括号中的任何字符。
下面两个表达式都匹配所有包含数字的字符串 在方括号内两个字符之间的连字符 (-) 可用来表示一系列字符其排序由字符的 Unicode 编号决定。在这种排序中字符 0 至 9 紧挨在一起代码 48 至 57因此 [0-9] 涵盖了所有字符并可与任何数字匹配。
一些常见字符组有自己的内置快捷键。数字就是其中之一 \d 与[0-9]的意思相同。 \d 只有包含数字字符为true否则为false \w 只有包含字母数字字符单词字符为true否则为false \s 只有包含空白字符空格、制表符、换行符及类似字符为true否则为false \D 只有数字为false否则为true \W 只有字母和数字为false否则为true \S 只有非空格、制表符、换行符及类似字符为false否则为true . 只有换行符(\t)为false否则为true
你可以用下面的表达式来匹配日期和时间格式如 01-30-2003 15:20 这个正则表达式看起来非常糟糕不是吗其中一半是反斜线产生了背景噪音很难发现实际表达的模式。稍后我们将看到这个表达式的一个稍加改进的版本。 这些反斜线代码也可以用在方括号内。例如[\d.] 表示任何数字或句点字符。方括号内的句号本身就失去了特殊含义。其他特殊字符也是如此如加号 ()。
要反转一组字符即表示要匹配除这组字符以外的任何字符可以在开头的括号后写入一个护理符 (^)。
不止0和1。 国际字符 由于 JavaScript 最初的实现比较简单而且这种简单的实现方式后来被固定为标准行为因此 JavaScript 的正则表达式对于英语中没有出现的字符非常迟钝。例如在 JavaScript 的正则表达式中“单词字符 ”仅指拉丁字母表中的 26 个字符大写或小写之一、十进制数字以及下划线字符。像 é 或 β 这样的字符肯定是单词字符但它们不会匹配 \w而会匹配大写字母 \W即非单词类别。 一个奇怪的历史巧合是\s空白不存在这个问题它可以匹配所有 Unicode 标准认为是空白的字符包括非破折空格和蒙古语元音分隔符。 在正则表达式中使用 \p 可以匹配 Unicode 标准指定了特定属性的所有字符。这样我们就能以一种更加国际化的方式匹配字母等字符。不过同样是出于与原始语言标准兼容的考虑只有在正则表达式后面加上 u 字符Unicode 标准时这些字符才能被识别。 \p{L} 任何字母字符 \p{N} 任何数字字符 \p{P} 任何标点符号 \P{L} 任何非字母大写 P 是反过来的 \p{ScriptHangul} 指定脚本中的任何字符参见第 5 章 使用 \w 进行文本处理可能需要处理非英语文本甚至是包含 “cliché ”等借词的英语文本但这是一种负担因为它不会将 “é ”等字符视为字母。虽然 \p 属性组比较啰嗦但它们更强大。 另一方面如果要对数字进行匹配以对其进行操作通常需要对数字进行匹配因为将任意数字字符转换为 JavaScript 数字并不是 Number 这样的函数所能完成的。
重复图案的某些部分 我们现在知道了如何匹配一个数字。如果我们想匹配一个整数--一个或多个数字的序列该怎么办呢 在正则表达式中如果在某个元素后加上加号 ()则表示该元素可能重复出现多次。因此/\d/ 可以匹配一个或多个数字字符。 匹配 1 次或多次 星号 (*) 具有类似的含义但也允许模式匹配零次。带有星号的内容永远不会阻止模式匹配--如果找不到合适的文本匹配它只会匹配零次。 匹配 0 次或多次 问号?表示模式中的某个部分是可选的这意味着它可能出现零次也可能出现一次。在下面的示例中u 字符是允许出现的但当它缺失时模式也会匹配 匹配 0 次或 1 次 要表示一个模式应出现的精确次数请使用大括号。例如在一个元素后面加上{4}就要求该元素必须出现四次。也可以用这种方法指定一个范围 {2,4}表示元素必须至少出现两次最多出现四次。
下面是日期和时间模式的另一个版本它允许使用一位数和两位数的日、月和小时。它也更容易解读。 使用大括号时也可以省略逗号后的数字指定开放式范围。例如{5,} 表示五次或五次以上。
分组子表达式 要同时对多个元素使用 * 或 等运算符必须使用括号。就后面的操作符而言正则表达式中被括号括起来的部分算作一个元素。 第一个和第二个 字符分别只适用于 boo 和 hoo 中的第二个 o。第三个 字符适用于整组 (hoo)可匹配一个或多个类似的序列。
示例中表达式末尾的 i 使该正则表达式不区分大小写可以匹配输入字符串中的大写 B即使该模式本身是全小写的。
匹配和分组 测试方法是匹配正则表达式的最简单方法。它只会告诉你是否匹配而不会告诉你其他信息。正则表达式还有一个 exec执行方法如果没有找到匹配该方法将返回空值否则将返回一个包含匹配信息的对象。 exec 返回的对象有一个索引属性它告诉我们成功匹配的字符串从哪里开始。除此之外该对象看起来像实际上也是一个字符串数组其第一个元素是匹配成功的字符串。在前面的示例中这就是我们要查找的数字序列。
字符串值也有类似的匹配方法。 当正则表达式包含用括号分组的子表达式时与这些分组匹配的文本也会显示在数组中。整个匹配总是第一个元素。下一个元素是与第一组表达式中开头括号在前的那一组匹配的部分然后是第二组依此类推。 console.log(/(he)(ll)(o)/.exec(hello));
输出
[hello,he,ll,o,index: 0,input: hello,groups: undefined
]
这句话的意思就是 数组的第一个元素总是整个匹配的结果 后续元素依次是每个分组匹配的内容。 如果一个分组最终没有被匹配例如后面跟了一个问号那么它在输出数组中的位置将保持未定义。当一个分组被多次匹配时例如后面有一个 只有最后一次匹配的分组才会出现在数组中。 console.log(/(\d)/.exec(123));//1-N
console.log(/(\d)*/.exec(123));//0-N
console.log(/(\d)?/.exec(123));//0-1
//输出
[ 123, 3, index: 0, input: 123, groups: undefined ]//返回最后一个
[ 123, 3, index: 0, input: 123, groups: undefined ]//返回最后一个
[ 1, 1, index: 0, input: 123, groups: undefined ]//返回第一个
如果只想使用括号进行分组而不想让它们显示在匹配数组中可以在开头的括号后加上? (?:...)表示一个非捕获组它不会在结果中产生单独的返回值。
组对于提取字符串的部分内容非常有用。如果我们不仅要验证字符串中是否包含日期还要提取日期并构建一个对象来表示日期那么我们可以在数字模式周围加上括号然后直接从执行结果中提取日期。
不过我们首先要绕个弯讨论一下 JavaScript 中表示日期和时间值的内置方法。
日期类 JavaScript 有一个标准的 Date 类用于表示日期或时间点。只要使用 new 创建一个日期对象就能得到当前的日期和时间。 您还可以为特定时间创建对象。 JavaScript 使用的惯例是月号从 0 开始因此 12 月是 11而日号从 1 开始。这种做法既混乱又愚蠢。要小心。
最后四个参数小时、分钟、秒和毫秒是可选的如果没有给出则视为零。
时间戳以 UTC 时区自 1970 年开始的毫秒数存储。这遵循了 “Unix 时间 ”的约定“Unix 时间 ”是在那个时候发明的。1970 年之前的时间可以使用负数。日期对象上的 getTime 方法会返回这个数字。可以想象这个数字很大。 如果给 Date 构造函数一个参数该参数将被视为毫秒计数。您可以通过创建一个新的 Date 对象并调用 getTime 或调用 Date.now 函数来获取当前毫秒数。
Date 对象提供了 getFullYear、getMonth、getDate、getHours、getMinutes 和 getSeconds 等方法来提取其组成部分。除了 getFullYear 方法还有 getYear 方法它提供的是年份减去 1900如 98 或 125后的值基本没有什么用处。
在表达式中我们感兴趣的部分加上括号就可以从字符串中创建日期对象了。 下划线 (_) 绑定将被忽略仅用于跳过 exec 返回的数组中的完整匹配元素。
边界和前瞻 不幸的是getDate 也可以从字符串 “100-1-30000 ”中提取日期。匹配可能发生在字符串的任何地方因此在这种情况下它只会从第二个字符开始到倒数第二个字符结束。 如果我们想强制要求匹配必须跨越整个字符串可以添加标记符 ^ 和 $。 粗体符匹配输入字符串的起点而美元符号匹配输入字符串的终点。因此/^\d$/ 会匹配完全由一个或多个数字组成的字符串/^!/ 会匹配任何以感叹号开头的字符串而 /x^/ 则不会匹配任何字符串字符串开头前不能有 x。 还有一种 \b 标记用于匹配单词边界即一边是单词字符另一边是非单词字符的位置。遗憾的是这些标记使用了和\w 一样简单的单词字符概念因此不是很可靠。
请注意这些边界标记并不匹配任何实际字符。它们只是强制执行给定条件在模式中出现的位置成立。 前瞻测试也有类似的功能。它们提供了一个模式如果输入与该模式不匹配就会导致匹配失败但实际上并不向前移动匹配位置。它们写在 (? 和) 之间。
来自GPT的解释
边界符号^ 表示字符串的开始$ 表示字符串的结束。因此正则表达式 /^\d$/ 意思是“匹配整个字符串必须完全由一个或多个数字组成”。例如“123”会匹配但“100-1-30000”不会因为后者不是完全由数字构成。\b 是单词边界表示单词字符字母、数字或下划线和非单词字符之间的边界。比如\bword\b 只会匹配“word”而不会匹配“sword”或“wording”。前瞻lookahead前瞻用于检查某个模式是否出现在当前匹配位置之后但并不实际消耗字符。例如(?pattern) 会检查后面是否有“pattern”但不会将其包含在匹配结果中。比如正则表达式 \d(?abc) 会匹配后面跟着“abc”的数字但匹配结果中不会包括“abc”。 第一个示例中的 e 是匹配所必需的但不是匹配字符串的一部分。(?! ) 表示否定的前瞻性第二个示例只匹配后面没有空格的字符。
选择模式 比方说我们想知道一段文字中是否不仅包含一个数字而且数字后面还包含猪、牛、鸡中的一个单词或它们的复数形式。 我们可以编写三个正则表达式然后依次测试它们但有一个更好的方法。管道符 (|) 表示在左边的模式和右边的模式之间进行选择。我们可以在这样的表达式中使用它 括号可用于限制管道运算符所适用的模式部分您还可以将多个此类运算符放在一起在两个以上的备选方案中进行选择。
匹配机制 从概念上讲当您使用 exec 或 test 时正则表达式引擎会在字符串中寻找匹配项首先尝试从字符串的开头开始匹配表达式然后从第二个字符开始依此类推直到找到匹配项或到达字符串的末尾。它要么会返回能找到的第一个匹配项要么根本找不到任何匹配项。
为了进行实际匹配引擎会像处理流程图一样处理正则表达式。这是上例中家畜表达式的流程图 如果我们能找到一条从图的左边到右边的路径那么我们的表达式就匹配了。我们在字符串中保留一个当前位置每次移动经过一个方框时我们都要验证当前位置后的字符串部分是否与该方框匹配。
回溯 正则表达式 /^([01]b|[\da-f]h|\d)$/ 可以匹配后跟 b 的二进制数、后跟 h 的十六进制数即 16 进制字母 a 至 f 代表数字 10 至 15或者不带后缀字符的十进制数。这就是相应的图表 在匹配这个表达式时即使输入的内容实际上并不包含二进制数也往往会输入最上面的二进制分支。例如在匹配字符串 “103 ”时只有在匹配到 3 时才会发现我们进入了错误的分支。该字符串确实与表达式匹配只是与我们当前所在的分支不匹配。 因此匹配器会回溯。当进入一个分支时它会记住当前位置在本例中位于字符串的起点刚刚经过图中的第一个边界框这样如果当前分支不成功它就可以返回并尝试另一个分支。对于字符串 “103”在遇到 3 字符后匹配器开始尝试十六进制数字分支但由于数字后面没有 h所以再次失败。然后它又尝试十进制数分支。这个分支符合要求最终报告了一个匹配结果。 一旦发现完全匹配匹配器就会停止。这意味着如果有多个分支可能匹配一个字符串则只使用第一个分支按分支在正则表达式中出现的位置排序。 回溯也会发生在 和 * 等重复运算符上。如果将 /^.*x/ 与 “abcxe ”匹配.* 部分将首先尝试使用整个字符串。然后引擎会意识到它需要一个 x 来匹配该模式。由于字符串末尾没有 x星形运算符会尝试匹配少一个字符。但是匹配器在 abcx 之后也没有找到 x因此它再次回溯将星形运算符匹配到 abc。现在它在需要的地方找到了一个 x并报告从 0 到 4 位置的匹配成功。 正则表达式可以进行大量的回溯。当一个模式能以多种不同的方式匹配一段输入时就会出现这个问题。例如如果我们在编写二进制正则表达式时感到困惑可能会不小心写成 /([01])b/ 这样的表达式。 如果试图匹配一长串没有尾部 b 字符的 0 和 1匹配器会先通过内循环直到用完所有数字。然后它注意到没有 b于是回退一个位置通过一次外循环然后再次放弃试图再次从内循环中回退。它将继续尝试通过这两个循环的所有可能路径。这意味着每增加一个字符工作量就会增加一倍。即使只有几十个字符匹配也会耗费很长时间。
替换法
字符串值有一个 replace 方法可用于用另一个字符串替换部分字符串。 第一个参数也可以是正则表达式在这种情况下正则表达式的第一个匹配项将被替换。如果在正则表达式后添加 g 选项表示全局字符串中的所有匹配都会被替换而不仅仅是第一个匹配。 将正则表达式与替换结合使用的真正优势在于我们可以在替换字符串中引用匹配的组。例如我们有一个包含人名的大字符串每行一个人名格式为 Lastname, Firstname。如果我们想交换这些名字并去掉逗号以获得 Firstname Lastname 格式我们可以使用下面的代码 替换字符串中的 $1 和 $2 指的是模式中的括号组。$1替换为与第一组匹配的文本$2替换为与第二组匹配的文本依此类推直至 $9。
替换的第二个参数可以是函数而不是字符串。每次替换时都会调用函数并将匹配组以及整个匹配作为参数然后将函数的返回值插入新字符串。
这里有一个例子 这段代码接收一个字符串查找所有出现的数字后跟字母数字单词然后返回一个字符串该字符串中的每一个数字都少一个。
(\d) 组最终作为函数的金额参数而 (\p{L}) 组则与单位绑定。函数会将 amount 转换为数字--这总是有效的因为它之前匹配了 \d并在只剩下一个或零的情况下做了一些调整。
贪婪 我们可以使用 replace 来编写一个函数删除 JavaScript 代码中的所有注释。下面是第一次尝试 操作符 | 之前的部分匹配两个斜线字符后面是任意数量的非新行字符。多行注释的部分涉及的内容更多。我们使用 [^]不在空字符集中的任何字符来匹配任何字符。这里我们不能只使用句号因为块注释可以在新行中继续而句号字符不能匹配换行符。
但最后一行的输出似乎出了问题。为什么呢 正如我在 “回溯 ”一节中所述表达式的 [^]* 部分将首先尽可能多地匹配。如果这导致模式的下一部分失败匹配器就会向后移动一个字符然后从那里重新开始匹配。在示例中匹配器首先尝试匹配整个字符串的其余部分然后从这里开始向后移动。在后退 4 个字符后它会找到 */ 的出现并进行匹配。这并不是我们想要的结果--我们的目的是匹配单个注释而不是一直匹配到代码末尾找到最后一个注释块的末尾。 由于这种行为我们说重复运算符、*、?和 {}是贪婪的这意味着它们会尽可能多地匹配并从那里开始回溯。如果在它们后面加上问号(?, *?, ??, {}?)它们就会变得不贪心开始时尽可能少匹配只有当剩余的模式不适合较小的匹配时才会匹配更多。 在这种情况下这正是我们想要的。通过让星号匹配到 */ 的最小字符段我们只消耗了一个注释块而没有更多。 正则表达式程序中的许多错误都可以追溯到无意中使用了贪婪运算符而非贪婪运算符的效果会更好。在使用重复运算符时应首选非贪婪变体。
动态创建 RegExp 对象 在某些情况下您在编写代码时可能不知道需要匹配的确切模式。例如您想测试一段文本中的用户姓名。您可以创建一个字符串然后使用 RegExp 构造函数。 在创建字符串中的\s 部分时我们必须使用两个反斜线因为我们是将它们写入普通字符串而不是斜线包围的正则表达式。RegExp 构造函数的第二个参数包含正则表达式的选项在本例中“gi ”表示全局和大小写不敏感。
但如果用户的名字是 “deahl[]rd ”呢这样就会产生一个毫无意义的正则表达式实际上无法匹配用户的姓名。
为了解决这个问题我们可以在任何具有特殊含义的字符前添加反斜线。 搜索方法 虽然字符串的 indexOf 方法不能使用正则表达式调用但另一种方法 search 可以使用正则表达式。和 indexOf 一样它也会返回找到正则表达式的第一个索引如果没有找到则返回-1。 遗憾的是我们无法指出匹配应从给定的偏移量开始就像我们可以使用 indexOf 的第二个参数一样而这通常是有用的。
lastIndex 属性 exec方法同样没有提供从字符串中给定位置开始搜索的便捷方法。但它提供了一种不方便的方法。 正则表达式对象具有属性。其中一个属性是 source它包含创建表达式的字符串。另一个属性是 lastIndex在某些有限的情况下它控制着下一个匹配将从哪里开始。 在这些情况下正则表达式必须启用全局g或粘性y选项并且必须通过执行方法进行匹配。同样如果能允许向 exec 传递一个额外的参数就可以减少混乱但混乱是 JavaScript 正则表达式接口的一个基本特征。 如果匹配成功exec 调用会自动更新 lastIndex 属性使其指向匹配结果之后1。如果没有找到匹配结果lastIndex 将被设回 0这也是它在新构建的正则表达式对象中的值。 全局选项和粘性选项的区别在于启用粘性选项后只有直接从 lastIndex 开始匹配才会成功而启用全局选项后匹配会提前搜索可以开始匹配的位置。lastIndex表示开始搜索的位置 在多个执行调用中使用共享的正则表达式值时这些对 lastIndex 属性的自动更新可能会导致问题。你的正则表达式可能会意外地从上一次调用留下的索引开始。 全局选项的另一个有趣作用是改变了字符串匹配方法的工作方式。当使用全局表达式调用时match 不会返回一个类似于 exec 所返回的数组而是会查找字符串中所有与模式匹配的字符串并返回一个包含匹配字符串的数组。 因此请谨慎使用全局正则表达式。在需要使用全局正则表达式的情况下--调用替换和需要显式使用 lastIndex 的地方--通常需要使用全局正则表达式。
常见的做法是在字符串中查找正则表达式的所有匹配项。我们可以使用 matchAll 方法来实现这一目的。 此方法返回一个匹配数组。为 matchAll 提供的正则表达式必须启用 g。
解析 INI 文件 在本章的最后我们将讨论一个需要使用正则表达式的问题。想象一下我们正在编写一个程序从互联网上自动收集敌人的信息。(在这里我们不会实际编写该程序而只是编写读取配置文件的部分。对不起。配置文件看起来是这样的 这种格式是一种广泛使用的文件格式通常称为 INI 文件其具体规则如下
空行和以分号开头的行将被忽略。以[]包装的行开始一个新的部分。包含字母数字标识符和 字符的行在当前部分添加一个设置。其他均无效。 我们的任务是将这样一个字符串转换成一个对象该对象的属性包含写在第一个章节标题之前的设置字符串和章节的子对象这些子对象包含章节的设置。 由于格式必须逐行处理因此将文件分割成不同行是一个好的开始。我们在第 4 章中看到了分割方法。不过有些操作系统不仅使用换行符来分行还使用换行后的回车符“\r\n”。鉴于 split 方法也允许使用正则表达式作为其参数我们可以使用类似 /\r?\n/ 这样的正则表达式来分割这样就可以在行间同时使用“\n ”和“\r\n”。 代码会遍历文件的每一行并建立一个对象。顶部的属性直接存储在该对象中而章节中的属性则存储在单独的章节对象中。章节绑定指向当前章节的对象。 有两种重要的行--节标题行或属性行。当一行是常规属性时它被存储在当前节中。如果是节标题则会创建一个新的节对象并将节设置为指向它。 注意反复使用 ^ 和 $ 是为了确保表达式匹配整行而不仅仅是其中的一部分。如果不使用这两种表达式代码在大多数情况下都能正常工作但在某些输入情况下却会出现奇怪的行为这可能是一个难以追踪的错误。 if (match string.match(...))模式利用了赋值表达式 () 的值就是赋值这一事实。我们通常无法确定对 match 的调用是否会成功因此只能在 if 语句中测试这一点才能访问结果对象。为了不破坏令人愉快的 else if 表单链我们将匹配的结果赋值给一个绑定并立即使用该赋值作为 if 语句的测试。 如果一行不是章节标题或属性函数会使用表达式 /^\s*(;|$)/ 检查它是注释还是空行以匹配只包含空白或空白后有分号使行的其余部分成为注释的行。如果一行不符合任何预期形式函数就会抛出异常。
代码单位和字符 JavaScript 正则表达式中的另一个标准化设计错误是在默认情况下. 或 ? 等运算符的作用对象是代码单元如第 5 章所述而不是实际字符。这意味着由两个代码单元组成的字符会表现得很奇怪。 问题在于第一行中的“ ”被视为两个代码单元而{3}只应用于第二个单元。同样圆点匹配的是一个代码单 元而不是组成玫瑰表情符号的两个代码单元。
您必须在正则表达式中添加 uUnicode选项以使其正确处理此类字符。 总结
正则表达式是表示字符串模式的对象。它们使用自己的语言来表达这些模式。
/abc/ 字符序列
/[abc]/ 一组字符中的任何字符
/[^abc]/ 不在字符集中的任何字符
/[0-9]/ 字符范围内的任何字符
/x/ 模式 x 的一次或多次出现
/x?/ 一次或多次出现无冗余
/x*/ 零次或多次出现
/x?/ 零次或一次出现
/x{2,4}/ 出现 2 到 4 次
/(abc)/ 一组
/a|b|c/ 几种模式中的任意一种
/d/ 任何数字字符
/w/ 字母数字字符单词字符
/s/ 任何空白字符
/./ 除换行符外的任何字符
/\ 任何字母字符
/^/ 输入开始
/$/ 输入结束
/(?a)/ 前瞻性测试 正则表达式有一个 test 方法用于测试给定字符串是否与之匹配。正则表达式还有一个 exec 方法当找到匹配时它会返回一个包含所有匹配组的数组。该数组有一个索引属性表示匹配从哪里开始。 字符串有一个 match 方法用于与正则表达式匹配还有一个 search 方法用于搜索正则表达式只返回匹配的起始位置。它们的 replace 方法可以用替换字符串或函数替换与模式匹配的字符串。 正则表达式可以有选项选项写在斜线后。i 选项使匹配不区分大小写。g 选项使表达式成为全局表达式除其他外这将导致 replace 方法替换所有实例而不仅仅是第一个实例。y 选项使表达式具有粘性这意味着在查找匹配时它不会向前搜索和跳过字符串的一部分。u 选项开启了 Unicode 模式启用了 \p 语法并修复了处理占用两个代码单元的字符时出现的一些问题。 正则表达式是一种锋利的工具但使用起来并不方便。正则表达式极大地简化了某些任务但在应用于复杂问题时很快就会变得难以驾驭。要知道如何使用正则表达式部分工作就是要克制自己的冲动不要把正则表达式无法表达的东西硬塞进正则表达式中。
练习 在进行这些练习的过程中你几乎不可避免地会对某些正则表达式莫名其妙的行为感到困惑和沮丧。有时将正则表达式输入到 debuggex.com 等在线工具中看看它的可视化是否符合你的意图并尝试它对各种输入字符串的响应方式会对你有所帮助。
Regexp 高尔夫 代码高尔夫是指用尽可能少的字符来表达特定程序的游戏。同样“正则表达式高尔夫 ”也是指编写尽可能少的正则表达式来匹配给定的模式而且只能匹配该模式。 请为下列每个项目编写一个正则表达式以测试给定模式是否出现在字符串中。正则表达式应只匹配包含该模式的字符串。当您的表达式有效时看看是否可以将其变得更小。
规则要求
car 和 catpop 和 propferretferry和ferrari任何以 ious 结尾的单词空白字符后面跟句号、逗号、冒号或分号超过6个字母的单词没有字母 e或 E的单词
请参考本章摘要中的表格以获得帮助。用几个测试字符串测试每个解决方案。
// Fill in the regular expressionsverify(/.../,[my car, bad cats],[camper, high art]);verify(/.../,[pop culture, mad props],[plop, prrrop]);verify(/.../,[ferret, ferry, ferrari],[ferrum, transfer A]);verify(/.../,[how delicious, spacious room],[ruinous, consciousness]);verify(/.../,[bad punctuation .],[escape the period]);verify(/.../,[Siebentausenddreihundertzweiundzwanzig],[no, three small words]);verify(/.../,[red platypus, wobbling nest],[earth bed, bedrøvet abe, BEET]);function verify(regexp, yes, no) {// Ignore unfinished exercisesif (regexp.source ...) return;for (let str of yes) if (!regexp.test(str)) {console.log(Failure to match ${str});}for (let str of no) if (regexp.test(str)) {console.log(Unexpected match for ${str});}
}
答案
verify(/(car|cat)/, [my car, bad cats], [camper, hight art]);
verify(/(pop|prop)/,[pop culture, mad props],[plop, prrrop]);
verify(/(ferret|ferry|ferrari)/,[ferret, ferry, ferrari],[ferrum, transfer A]);
verify(/\b\w*ious\b/,[how delicious, spacious room],[ruinous, consciousness]);
verify(/\b\s(.|;|:|,)\b/, [bad punctuation .], [escape the period]);
verify(/\b\w{6,}\b/, [Siebentausenddreihundertzweiundzwanzig], [no, three small words]);
verify(/\b(?!\w*e)(?!\w*E)\w\b/, [red platypus, wobbling nest], [earth bed, bedrøvet abe, BEET]);