【译】JavaScript 开发者的正则表达式系列篇(4)

如何在 JavaScript 中创建正则表达式

在 JavaScript 中创建正则表达式有两种方法。第一个是使用正则表达式文字语法,第二个是使用 RegExp() 构造函数。

要使用正则表达式文字语法创建正则表达式,您必须将模式括在两个正斜杠 ( / ) 内,如下所示:

js 复制代码
/regex pattern/ 

如果你想使用一个或多个标志,它必须在第二个斜杠之后:

js 复制代码
/regex pattern/flag

根据您的用例,您可能必须将正则表达式分配给变量:

js 复制代码
const regex = /regex pattern/flag

该标志可以是 JavaScript 正则表达式引擎中可用的任何标志。

如果要使用 RegExp() 构造函数创建正则表达式,则必须使用 new 关键字,然后将模式和标志放在 RegExp() 括号内。

语法如下:

js 复制代码
const regex = new RegExp("regex pattern", "flag");

由于 RegExp() 是一个构造函数,因此其中有一些方法和属性可供您使用正则表达式。无论您使用文字语法 // 还是 RegExp() 构造函数创建模式,方法和属性都可用。

RegExp() 构造函数的方法

RegExp() 构造函数的方法在 RegExp.prototype 上定义。您可以通过在浏览器控制台中键入 RegExp().__proto__ 并点击 ENTER 来快速检查方法(和属性)。这些方法包括 test()exec()toString()

除了这三个之外,有些方法还采用正则表达式作为参数。但最好在"使用正则表达式的字符串方法"下讨论它们,因为它们的核心是采用正则表达式作为参数的字符串方法。

Let's take a look at what test(), exec(), and toString() do.

让我们看看 test()exec()toString() 做了什么。

The test() Method test() 方法

test() 方法测试正则表达式和测试字符串之间的匹配,并返回一个布尔值作为结果。如果匹配,则返回 true ,如果不匹配,则返回 false

在下面的示例中,有一个模式 /freeCodeCamp/ 的匹配:

js 复制代码
const re = /freeCodeCamp/;
const testStr =
  "freeCodeCamp doesn't charge you any money, that's why it's called freeCodeCamp.";

console.log(re.test(testStr)); //true

但在下面的示例中,模式 /fcc/ 不匹配,因此 test() 方法返回 false

js 复制代码
const re = /fcc/;
const testStr =
  "freeCodeCamp doesn't charge you any money, that's why it's called freeCodeCamp.";

console.log(re.test(testStr)); //false

除了针对字符串测试随机模式之外, test() 方法在表单验证中也很有用。

The exec() Method exec() 方法

exec() 方法在测试字符串中执行匹配搜索,并返回一个包含有关第一个匹配的详细信息的数组。如果没有匹配,则返回 null

这是一个例子:

js 复制代码
const re = /freeCodeCamp/;
const testStr =
 "freeCodeCamp doesn't charge you any money, that's why it's called freeCodeCamp.";

console.log(re.exec(testStr));

这是结果的屏幕截图:

如果您想让 exec() 方法返回所有匹配项,您可以在模式上使用 g 标志,然后使用 while 循环进行循环:

js 复制代码
const re = /freeCodeCamp/g;
const testStr =
  "freeCodeCamp is a great place to start learning to code from scratch. freeCodeCamp doesn't charge you any money, that's why it's called freeCodeCamp.";

let match;

while ((match = re.exec(testStr)) !== null) {
  console.log(match[0]);
}

结果在控制台中如下所示:

您可以通过以下方式访问匹配项的索引来进一步进行操作:

js 复制代码
const re = /freeCodeCamp/g;
const testStr =
  "freeCodeCamp is a great place to start learning to code from scratch. freeCodeCamp doesn't charge you any money, that's why it's called freeCodeCamp.";

let match;

while ((match = re.exec(testStr)) !== null) {
  console.log(match[0]);

  //   Access the indices of the matches
  console.log(match.index);
}

如果没有匹配, exec() 返回 null:

js 复制代码
const re = /fcc/;
const testStr =
  "freeCodeCamp doesn't charge you any money, that's why it's called freeCodeCamp.";

console.log(re.exec(testStr)); //null

The toString() Method toString() 方法

toString() 方法将正则表达式模式转换为字符串。在 JavaScript 中, toString() 方法存在于每个对象中。正则表达式被视为幕后的对象,这就是为什么您可以使用 new 关键字创建它们。

在正则表达式模式上使用此方法会将模式转换为字符串:

js 复制代码
const pattern = /freeCodeCamp/;
const strPattern = pattern.toString();

console.log(strPattern, typeof strPattern); // /freeCodeCamp/ string

即使您使用 RegExp() 构造函数创建模式,您也会以相同的方式获得结果:

js 复制代码
const pattern = new RegExp('freeCodeCamp');
const strPattern = pattern.toString();

console.log(strPattern, typeof strPattern); // /freeCodeCamp/ string

如果模式中有一个标志,它将作为字符串的一部分返回:

js 复制代码
const pattern = /freeCodeCamp/gi;
const strPattern = pattern.toString();

console.log(strPattern, typeof strPattern); // /freeCodeCamp/gi string

RegExp() 构造函数的属性

RegExp() 构造函数的属性在 RegExp.prototype 上定义。他们包括:

  • RegExp.prototype.global
  • RegExp.prototype.source
  • RegExp.prototype.flags
  • RegExp.prototype.multiline
  • RegExp.prototype.ignoreCase
  • RegExp.prototype.dotAll
  • RegExp.prototype.sticky
  • RegExp.prototype.unicode

简而言之,有 globalsourceflagsmultilineignoreCasedotAllunicode 。 大多数属性检查是否使用某个标志。让我们看一下每个属性的工作原理。

global 属性

全局属性检查 g 标志是否与正则表达式模式一起使用。如果模式具有 g 标志,则返回 true ,否则返回 false

请记住 global ( g ) 标志指示正则表达式模式不应仅返回第一个匹配项,而应返回所有匹配项。 以下是 global 属性在代码中的工作原理:

js 复制代码
const re1 = /freeCodeCamp/g;
const re2 = /freeCodeCamp/;
const re3 = new RegExp('freeCodeCamp');
const re4 = new RegExp('freeCodeCamp', 'g');

console.log(re1.global); //true
console.log(re2.global); //false
console.log(re3.global); //false
console.log(re4.global); //true

flag 属性

flag 属性按字母顺序返回您在正则表达式模式中使用的标志。也就是说, gi 之前, im 之前, my 之前, 等等。

在下面的代码中,您可以看到 g 标志位于 i 之前,而 m 位于 y 之前:

js 复制代码
const re1 = /freeCodeCamp/gi;
const re2 = new RegExp('freeCodeCamp', 'my');

console.log(re1.flags); //gi
console.log(re2.flags); //my

source 属性

source 属性以字符串形式返回正则表达式模式。因此,它的行为类似于 toString() 方法。 source 属性和 toString() 方法之间的区别在于 source 属性排除了与模式一起使用的标志。此外, source 属性不显示用于创建正则表达式的文字正斜杠。

在下面的代码中,您可以看到正斜杠没有被打印,标志也被省略,并且 type 是一个字符串:

js 复制代码
const re1 = /freeCodeCamp/gi;
const re2 = new RegExp('freeCodeCamp', 'my');

const re1Source = re1.source;
const re2Source = re2.source;

console.log(re1Source, typeof re1Source); // freeCodeCamp string
console.log(re2Source, typeof re2Source); // freeCodeCamp string

multiline 属性

multiline 标志是 RegExp() 构造函数的另一个布尔属性。它通过返回 truefalse 来指定 multiline 标志是否与模式一起使用。

请记住 multiline ( m ) 标志指示测试字符串应被视为具有多行的文本。 以下是 multiline 属性的实际工作原理:

js 复制代码
const re1 = /freeCodeCamp/gi;
const re2 = new RegExp('freeCodeCamp', 'my');

const re1Source = re1.multiline;
const re2Source = re2.multiline;

console.log(re1Source); //false
console.log(re2Source); // true

ignoreCase 属性

ignoreCase 属性指定是否在正则表达式模式中使用不区分大小写的标志 ( i )。如果您使用 i 标志,它会返回 true ;如果您不使用它,它会返回 false

js 复制代码
const re1 = /freeCodeCamp/i;
const re2 = /freeCodeCamp/;
const re3 = new RegExp('freeCodeCamp', 'i');
const re4 = new RegExp('freeCodeCamp');

console.log(re1.ignoreCase); //true
console.log(re2.ignoreCase); // false
console.log(re3.ignoreCase); // true
console.log(re4.ignoreCase); // false

Unicode 属性

unicode 属性可帮助您检查正则表达式模式中是否使用 Unicode ( u ) 标志。如果找到 u 标志,则返回 true ,否则返回 false

js 复制代码
const re1 = /\u{1F1F3}\u{1F1EC}/u; //matches the Nigerian flag emoji
const re2 = /\u{1F1F3}\u{1F1EC}/;
const re3 = new RegExp('\u{1F1F3}\u{1F1EC}', 'u');
const re4 = new RegExp('\u{1F1F3}\u{1F1EC}');

console.log(re1.unicode); //true
console.log(re2.unicode); // false
console.log(re3.unicode); // true
console.log(re4.unicode); // false

sticky 属性

Sticky 属性指示是否在正则表达式中设置了粘性 ( y ) 标志。尽管这就是它的作用,但由于 lastIndex 属性,理解它仍然有点棘手。

设置 y 标志时,正在使用的正则表达式引擎将尝试匹配从 lastIndex 属性指定的确切位置开始的模式(不使用 g 标志)。如果找到匹配项, lastIndex 属性将立即更新为匹配结束后的位置。

为了帮助您更好地理解这一点,这里有一个带有注释的代码片段:

js 复制代码
const re = /xyz/y;
const str = 'xyzxyz';

re.lastIndex = 0;
console.log(re.test(str)); // true -- there's a match at index 0 to 2
console.log(re.lastIndex); // 3

re.lastIndex = 1;
console.log(re.test(str)); // false -- no match at the specified index
console.log(re.lastIndex); // 0 -- resets to 0 because there's no match at the specified index

re.lastIndex = 3;
console.log(re.test(str)); // true -- there's a match at index 3 to 5
console.log(re.lastIndex); // 6

re.lastIndex = 6;
console.log(re.test(str)); // false
console.log(re.lastIndex); // 0 -- resets to 0 because there's no match at the specified index

注意: dotAll 属性与通配符 ( . ) 元字符一起使用。因此,您将在元字符章节中详细了解它的工作原理。此外, hasIndices 还可以用于捕获。因此,您将在分组和捕获章节中了解如何使用它。

使用正则表达式的字符串方法

JavaScript 提供了一些处理字符串的内置方法。其中一些方法将正则表达式作为参数。这些方法包括 match()matchAll()replace()replaceAll()split()search() . 让我们一一看看。

search() 方法

search() 方法在字符串中搜索正则表达式的匹配项并返回匹配项的索引。

js 复制代码
const myStr =
  "fCC is the abbreviation for freeCodeCamp. freeCodeCamp doesn't charge you any money, that's why it's called freeCodeCamp. Learn to code for free today.";
const re = /freeCodeCamp/;
const searchFCC = myStr.search(re);

console.log(searchFCC); //28

如果 search() 方法找不到匹配项,则返回 -1

js 复制代码
const myStr =
  "fCC is the abbreviation for freeCodeCamp. freeCodeCamp doesn't charge you any money, that's why it's called freeCodeCamp. Learn to code for free today.";
const re = /FCC/;
const searchFCC = myStr.search(re);

console.log(searchFCC); //-1

您可能会认为将 g 标志与模式一起使用会返回所有匹配项的索引,但事实并非如此。 g 标志不会影响 search() 方法:

ini 复制代码
const myStr =
  "fCC is the abbreviation for freeCodeCamp. freeCodeCamp doesn't charge you any money, that's why it's called freeCodeCamp. Learn to code for free today.";
const re = /freeCodeCamp/g; //pattern with g flag
const searchFCC = myStr.search(re);

console.log(searchFCC); //28

如果你想获取所有匹配的索引,你应该使用 match()matchAll() 方法。

match() 方法

match() 方法允许您指定正则表达式模式作为参数,然后它遍历您使用它的字符串,并返回一个包含与正则表达式模式匹配的子字符串的数组。

js 复制代码
const my_str = 'freeCodeCamp';
match = my_str.match(/free/);

console.log(match); // [ 'free', index: 0, input: 'freeCodeCamp', groups: undefined ]

您还可以将正则表达式模式分离到一个单独的变量中:

js 复制代码
const my_str = 'freeCodeCamp';
const re = /free/;
const match = my_str.match(re);

console.log(match); // [ 'free', index: 0, input: 'freeCodeCamp', groups: undefined ]

如果 match() 找到多个匹配项,它会返回数组中的所有匹配项,前提是您在模式中使用 g 标志:

js 复制代码
const my_str =
  "freeCodeCamp doesn't charge you any money, that's why it's called freeCodeCamp. Learn to code for free today.";
const re = /free/g;
const match = my_str.match(re);

console.log(match); // ['free', 'free', 'free']

如果扩展数组,则如下所示:

由于结果是一个数组,您可能应该使用 console.table() 而不是 console.log() ,这样您就可以看到匹配的索引:

js 复制代码
const my_str =
  "freeCodeCamp doesn't charge you any money, that's why it's called freeCodeCamp. Learn to code for free today.";
const re = /free/g;
const match = my_str.match(re);

console.table(match); 

如果 match() 方法找不到匹配项,则返回 null

js 复制代码
const my_str = 'freeCodeCamp';
const re = /ref/;
const match = my_str.match(re);

console.log(match); // null

matchAll() 方法

matchAll()match() 方法的混合体。它返回与您提供的正则表达式匹配的所有子字符串的迭代器。这意味着您必须将其与 global ( g ) 标志一起使用。

因为它返回所有匹配项的迭代器,所以 matchAll() 是循环遍历正则表达式匹配项的绝佳选择。

迭代正则表达式匹配的另一种方法是使用 exec() 方法和 g 标志,然后以这种方式使用 while 循环进行循环:

js 复制代码
const my_str =
  "freeCodeCamp doesn't charge you any money, that's why it's called freeCodeCamp. Learn to code for free today.";
const re = /free/g;

let match;
while ((match = re.exec(my_str))) {
  console.log(match[0]); //
}

// free
// free
// free

使用 matchAll() 方法,您不需要 exec()while 循环。您只需要一个 for...of 循环来获取匹配项:

js 复制代码
const my_str =
  "freeCodeCamp doesn't charge you any money, that's why it's called freeCodeCamp. Learn to code for free today.";
const re = /free/g;
const matches = my_str.matchAll(re);

console.log(matches); // RegExpStringIterator {}

//loop through the matches with a for...of loop
for (const match of matches) {
  console.log(match);
}

这将返回每个 match 、它们的索引、测试字符串、长度以及各自数组中的组:

您可以修改控制台日志以仅获取匹配项及其索引:

js 复制代码
const my_str =
  "freeCodeCamp doesn't charge you any money, that's why it's called freeCodeCamp. Learn to code for free today.";
const re = /free/g;
const matches = my_str.matchAll(re);

console.log(matches); // RegExpStringIterator {}

//loop through the matches with a for...of loop
for (const match of matches) {
  console.log(`Found a match ${match[0]} at index ${match.index}`);
}

/*
Output:
Found a match free at index 0
Found a match free at index 66
Found a match free at index 98
*/

您还可以使用 Array.from() 方法执行相同的操作:

javascript 复制代码
const my_str =
  "freeCodeCamp doesn't charge you any money, that's why it's called freeCodeCamp. Learn to code for free today.";
const re = /free/g;

Array.from(my_str.matchAll(re), (match) =>
  console.log(`Found a match ${match[0]} at index ${match.index}`)
);

/*
Output:
Found a match free at index 0
Found a match free at index 66
Found a match free at index 98
*/

如果 matchAll() 方法找不到匹配项,则返回一个空迭代器。如果您决定循环遍历该空迭代器,则控制台中将看不到任何内容。

replace() 方法

replace() 方法的作用正如其名称所暗示的那样。它在字符串中搜索指定字符串或正则表达式的匹配项,并将其替换为指定的替换字符串。它返回一个应用了替换的新字符串。

replace() 方法不像 match()matchAll() 那样简单,因为它接受两个参数 - 正则表达式和替换字符串。然后,测试字符串中与正则表达式匹配的任何子字符串都将替换为替换字符串。

如果正则表达式不包含全局 ( g ) 标志,则仅替换第一个匹配项:

js 复制代码
const myStr =
  'Elephants are very large animals. They are large to the extent that they can uproot a large tree.';
const re = /large/;
const replaceLarge = myStr.replace(re, 'massive');

console.log(replaceLarge); // Elephants are very massive animals. They are large to the extent that they can uproot a large tree.

如果您在模式中使用 g 标志,则所有匹配项都会被替换:

js 复制代码
const myStr =
  'Elephants are very large animals. They are large to the extent that they can uproot a large tree.';
const re = /large/g;
const replaceLarge = myStr.replace(re, 'massive');

console.log(replaceLarge); // Elephants are very massive animals. They are massive to the extent that they can uproot a massive tree.

replaceAll() 方法

replaceAll() 方法相对较新,因为它在 ECMAScript 2021 中可用。它是 replace() 的混合体。 replace()replaceAll() 都通过将正则表达式和替换字符串作为参数来执行相同的操作,并用指定的替换字符串替换所有匹配项。

但与 replace() 不同,如果您不使用 g 标志,则只会替换第一个匹配项, replaceAll() 默认情况下会替换所有匹配项:

js 复制代码
const myStr =
  'Elephants are very large animals. They are large to the extent that they can uproot a large tree.';
const re = /large/g;
const replaceLarge = myStr.replaceAll(re, 'massive');

console.log(replaceLarge); // Elephants are very massive animals. They are massive to the extent that they can uproot a massive tree.

如果您不将 g 标志与 replaceAll() 一起使用,则会抛出 TypeError

js 复制代码
const myStr =
  'Elephants are very large animals. They are large to the extent that they can uproot a large tree.';
const re = /large/;
const replaceLarge = myStr.replaceAll(re, 'massive');

console.log(replaceLarge); // Uncaught TypeError: String.prototype.replaceAll called with a non-global RegExp argument
//    at String.replaceAll (<anonymous>)

split() 方法

split() 方法接受一个字符串或正则表达式,并根据您传递给它的字符串或正则表达式将您使用它的字符串拆分为一个数组。 split() 方法还采用可选的 limit 参数,即正数。当您指定 limit 时,分割将在该限制处停止。

无论 split() 在哪里找到匹配项,它都会在数组中创建一个新项目。它的工作原理如下:

js 复制代码
const myStr = "Codes don't lie. You're the one doing something wrong.";
const re = /\s/; // "\s" means white space - spacebar, backspace, tab, ENTER.

const splitedStr = myStr.split(re);
console.log(splitedStr);

/* 
Output:
[
  'Codes',  "don't",
  'lie.',   "You're",
  'the',    'one',
  'doing',  'something',
  'wrong.'
]
*/

以下是如何使用带有 limit 参数的 split() 方法:

js 复制代码
const myStr = "Codes don't lie. You're the one doing something wrong.";
const re = /\s/; // "\s" means white space - spacebar, backspace, tab, ENTER.

const splitedStr = myStr.split(re, 5); // 5 is the limit here
console.log(splitedStr);

/*
output: [ 'Codes', "don't", 'lie.', "You're", 'the' ]
*/

如何匹配 JavaScript 正则表达式中的文字字符

正如我之前指出的,文字字符是您将按原样编写模式的文本或字符串。

如果您想匹配文本 hello ,则 /hello/ 应该是您的模式。然后,您可以使用 i 标志来匹配 helloHello

js 复制代码
const testString = 'hello';
const re = /hello/;
const re2 = /hello/i;

console.log(re.test(testString)); // true
console.log(re2.test(testString)); // true

如果你想匹配 freeCodeCamp ,模式应该就是这样。您还可以创建在任何情况下都匹配 freeCodeCamp 的模式:

js 复制代码
const testString = 'freeCodeCamp';
const re = /freeCodeCamp/;
const re2 = /freeCodeCamp/i; // match freeCodeCamp in any case

console.log(re.test(testString)); // true
console.log(re2.test(testString)); // true

您还可以使用文字字符来匹配数字:

js 复制代码
const num = 10234;
const re = /2/;

console.log(re.test(num)); //true

如何在 JavaScript 正则表达式中使用字符集

提醒一下,字符集是用方括号括起来的一组字符。它们提供了一种指定一组字符的方法,正则表达式引擎可以根据这些字符来匹配测试字符串中特定位置的单个字符。

字符集允许您指定字符范围、单个字符或两者的组合。 以下是正则表达式中流行字符集的常见示例:

  • [abc] :匹配 abc
  • [aeiou] :匹配任何元音字符
  • [a-z] :匹配从 az 的任何小写字母
  • [A-Z] :匹配从 AZ 的任何大写字母 -[0-9] :匹配 0 到 9 之间的任意数字

我们来看看如何在 JavaScript 正则表达式中匹配上述各个字符集:

js 复制代码
// uppercase character set
const hcaseRe = /[A-Z]/;
const hcaseStr = 'freeCodeCamp is cool';

console.log(hcaseRe.test(hcaseStr)); //true

// vowels character set
const vowelsRe = /[aeiou]/;
const vowelsStr = 'Imagine how pronunciation would have been without vowels';

console.log(vowelsRe.test(vowelsStr)); //true

// [abc] character set
const abcSetRe = /[abc]/;
const abcSetStr = 'freeCodeCamp is totally free';

console.log(abcSetRe.test(abcSetStr)); //true

// number character set
const numRe = /[0-9]/;
const numStr = 'Thank God for Arabic numerals 0 to 9.';

console.log(numRe.test(numStr)); //true

在线工具

参考文献

相关推荐
DN金猿22 分钟前
vue项目PC端和移动端实现在线预览pptx文件
前端·javascript·vue.js·ppt
hahaqi952734 分钟前
layui 表格点击编辑感觉很好用,实现方法如下
前端·javascript·layui
我爱学习_zwj1 小时前
ArkTS的进阶语法-4(函数补充,正则表达式)
前端·华为·正则表达式·harmonyos
北【辰】、1 小时前
uview Collapse折叠面板无法动态设置展开问题(微信小程序)
javascript·vue.js·微信小程序·小程序·前端框架
cdcdhj1 小时前
利用服务工作线程serviceWorker缓存静态文件css,html,js,图片等的方法,以及更新和删除及版本控制
javascript·css·缓存·html
咔咔库奇1 小时前
【CSS问题】margin塌陷
前端·javascript·css
无敌最俊朗@2 小时前
c#————委托Action使用例子
java·前端·c#
见过夏天2 小时前
CSS 中渐变色的使用
前端·css
764332 小时前
JavaScript ES6 继承 class
前端·javascript
袁代码2 小时前
SwiftUI开发教程系列 - 第十二章:本地化与多语言支持
开发语言·前端·ios·swiftui·swift·ios开发