2022 年 8 月 7 日

交替(或) |

交替是正则表达式中的一个术语,实际上是一个简单的“或”。

在正则表达式中,它用竖线字符 | 表示。

例如,我们需要找到编程语言:HTML、PHP、Java 或 JavaScript。

相应的正则表达式:html|php|java(script)?

一个使用示例

let regexp = /html|php|css|java(script)?/gi;

let str = "First HTML appeared, then CSS, then JavaScript";

alert( str.match(regexp) ); // 'HTML', 'CSS', 'JavaScript'

我们已经看到了类似的东西——方括号。它们允许在多个字符之间进行选择,例如 gr[ae]y 匹配 graygrey

方括号只允许字符或字符类。交替允许任何表达式。正则表达式 A|B|C 表示表达式 ABC 之一。

例如

  • gr(a|e)ygr[ae]y 的含义完全相同。
  • gra|ey 表示 graey

要将交替应用于模式的选定部分,我们可以将其括在括号中。

  • I love HTML|CSS 匹配 I love HTMLCSS
  • I love (HTML|CSS) 匹配 I love HTMLI love CSS

示例:时间正则表达式

在之前的文章中,有一个构建正则表达式的任务,用于搜索 hh:mm 格式的时间,例如 12:00。但是简单的 \d\d:\d\d 太模糊了。它接受 25:99 作为时间(因为 99 分钟匹配模式,但该时间无效)。

我们如何构建更好的模式?

我们可以使用更细致的匹配。首先,是小时部分

  • 如果第一个数字是 01,那么下一个数字可以是任何数字:[01]\d
  • 否则,如果第一个数字是 2,那么下一个数字必须是 [0-3]
  • (不允许其他第一个数字)

我们可以使用交替在正则表达式中编写这两种变体:[01]\d|2[0-3]

接下来,分钟必须在 0059 之间。在正则表达式语言中,可以写成 [0-5]\d:第一个数字 0-5,然后是任何数字。

如果我们将小时和分钟粘合在一起,我们将得到模式:[01]\d|2[0-3]:[0-5]\d

我们快完成了,但有一个问题。交替 | 现在恰好发生在 [01]\d2[0-3]:[0-5]\d 之间。

也就是说:分钟被添加到第二个交替变体中,这里有一个清晰的图片

[01]\d  |  2[0-3]:[0-5]\d

该模式查找 [01]\d2[0-3]:[0-5]\d

但这是错误的,交替应该只用于正则表达式的“小时”部分,以允许 [01]\d2[0-3]。让我们通过将“小时”括在括号中来纠正这一点:([01]\d|2[0-3]):[0-5]\d

最终解决方案

let regexp = /([01]\d|2[0-3]):[0-5]\d/g;

alert("00:00 10:10 23:59 25:99 1:2".match(regexp)); // 00:00,10:10,23:59

任务

有很多编程语言,例如 Java、JavaScript、PHP、C、C++。

创建一个正则表达式,在字符串 Java JavaScript PHP C++ C 中找到它们。

let regexp = /your regexp/g;

alert("Java JavaScript PHP C++ C".match(regexp)); // Java JavaScript PHP C++ C

第一个想法是使用 | 将语言列出来。

但这不起作用

let regexp = /Java|JavaScript|PHP|C|C\+\+/g;

let str = "Java, JavaScript, PHP, C, C++";

alert( str.match(regexp) ); // Java,Java,PHP,C,C

正则表达式引擎逐个查找备选方案。也就是说:首先检查是否有 Java,否则 - 查找 JavaScript 等等。

因此,JavaScript 永远不会被找到,仅仅因为 Java 是第一个被检查的。

CC++ 也是如此。

这个问题有两个解决方案

  1. 更改顺序,先检查较长的匹配项: JavaScript|Java|C\+\+|C|PHP
  2. 合并具有相同开头的变体: Java(Script)?|C(\+\+)?|PHP

实际应用

let regexp = /Java(Script)?|C(\+\+)?|PHP/g;

let str = "Java, JavaScript, PHP, C, C++";

alert( str.match(regexp) ); // Java,JavaScript,PHP,C,C++

一个“bb-tag”看起来像 [tag]...[/tag],其中 tag 是以下之一:burlquote

例如

[b]text[/b]
[url]http://google.com[/url]

BB-tags 可以嵌套。但一个标签不能嵌套到自身,例如

Normal:
[url] [b]http://google.com[/b] [/url]
[quote] [b]text[/b] [/quote]

Can't happen:
[b][b]text[/b][/b]

标签可以包含换行符,这是正常的

[quote]
  [b]text[/b]
[/quote]

创建一个正则表达式来查找所有 BB-tags 及其内容。

例如

let regexp = /your regexp/flags;

let str = "..[url]http://google.com[/url]..";
alert( str.match(regexp) ); // [url]http://google.com[/url]

如果标签嵌套,那么我们需要外层标签(如果需要,我们可以继续在其内容中搜索)

let regexp = /your regexp/flags;

let str = "..[url][b]http://google.com[/b][/url]..";
alert( str.match(regexp) ); // [url][b]http://google.com[/b][/url]

开始标签是 \[(b|url|quote)]

然后要找到直到结束标签的所有内容 - 让我们使用带有 s 标志的模式 .*? 来匹配包括换行符在内的任何字符,然后添加对结束标签的反向引用。

完整模式: \[(b|url|quote)\].*?\[/\1]

实际应用

let regexp = /\[(b|url|quote)].*?\[\/\1]/gs;

let str = `
  [b]hello![/b]
  [quote]
    [url]http://google.com[/url]
  [/quote]
`;

alert( str.match(regexp) ); // [b]hello![/b],[quote][url]http://google.com[/url][/quote]

请注意,除了转义 [ 之外,我们还必须转义结束标签的斜杠 [\/\1],因为通常斜杠会关闭模式。

创建一个正则表达式来查找双引号中的字符串 "..."

字符串应该支持转义,与 JavaScript 字符串相同。例如,引号可以插入为 \",换行符为 \n,反斜杠本身为 \\

let str = "Just like \"here\".";

请注意,特别是转义的引号 \" 不会结束字符串。

因此,我们应该从一个引号搜索到另一个引号,忽略途中遇到的转义引号。

这是任务的本质部分,否则它将变得微不足道。

要匹配的字符串示例

.. "test me" ..
.. "Say \"Hello\"!" ... (escaped quotes inside)
.. "\\" ..  (double backslash inside)
.. "\\ \"" ..  (double backslash and an escaped quote inside)

在 JavaScript 中,我们需要将反斜杠加倍以将其正确传递到字符串中,如下所示

let str = ' .. "test me" .. "Say \\"Hello\\"!" .. "\\\\ \\"" .. ';

// the in-memory string
alert(str); //  .. "test me" .. "Say \"Hello\"!" .. "\\ \"" ..

解决方案:/"(\\.|[^"\\])*"/g

逐步

  • 首先,我们查找一个开头的引号 "
  • 然后,如果我们有一个反斜杠 \\(我们必须在模式中将其加倍,因为它是一个特殊字符),那么它之后的任何字符都可以(一个点)。
  • 否则,我们取除引号(这将意味着字符串的结束)和反斜杠(为了防止出现孤立的反斜杠,反斜杠仅与它后面的其他符号一起使用)以外的任何字符:[^"\\]
  • …以此类推,直到结束引号。

实际应用

let regexp = /"(\\.|[^"\\])*"/g;
let str = ' .. "test me" .. "Say \\"Hello\\"!" .. "\\\\ \\"" .. ';

alert( str.match(regexp) ); // "test me","Say \"Hello\"!","\\ \""

编写一个正则表达式来查找标签 <style...>。它应该匹配完整标签:它可能没有属性 <style> 或具有多个属性 <style type="..." id="...">

…但正则表达式不应该匹配 <styler>

例如

let regexp = /your regexp/g;

alert( '<style> <styler> <style test="...">'.match(regexp) ); // <style>, <style test="...">

模式的开头很明显:<style

…但我们不能简单地写 <style.*?>,因为 <styler> 会匹配它。

我们需要在 <style 之后有一个空格,然后可选地是其他内容,或者结束的 >

在正则表达式语言中:<style(>|\s.*?>)

实际应用

let regexp = /<style(>|\s.*?>)/g;

alert( '<style> <styler> <style test="...">'.match(regexp) ); // <style>, <style test="...">
教程地图

评论

在评论之前阅读…
  • 如果您有任何改进建议,请提交 GitHub 问题或拉取请求,而不是评论。
  • 如果您不理解文章中的某些内容,请详细说明。
  • 要插入少量代码,请使用<code>标签,对于多行代码,请将其包裹在<pre>标签中,对于超过10行的代码,请使用沙盒(plnkrjsbincodepen…)