正则表达式学习
- 1.能干嘛
- 2.创建正则表达式
- 3.关于正则表达式的方法
- 3.1 正则的方法
- 3.1.1 test
- 3.1.2 compile
- 3.1.3 exec
- 捕获组对象
- 具名捕获组对象
- 非捕获组对象
- 3.2 String类型的对象的正则相关的方法
- 3.2.1 search()
- 3.2.2 replace()
- 3.2.3 split()
- 3.2.4 match()
- 3.2.5 matchAll()
1.能干嘛
作为一个前端也不能不会正则表达式,它能干嘛呢。主要就是验证和对数据就行抽离替换吧
2.创建正则表达式
你可以使用以下两种方法构建一个正则表达式:
使用一个正则表达式字面量,其由包含在斜杠之间的模式组成,如下所示:
var re = /g-s/;
或者调用RegExp对象的构造函数来创建正则:
var re = new RegExp("ab+c");
两种方法都是可以的,但是第二种更强一点,它可以动态变化,例如
const pattern = "hello";
const modifiers = "gi";
const dynamicRegex = new RegExp(pattern, modifiers);
可以根据具体的需求,在构造函数中使用变量或动态生成的字符串来创建正则表达式。但是也要注意了,如果你需要在运行时动态改变正则表达式的模式或修饰符,你需要重新创建一个新的正则表达式对象。
let pattern = "hello";
let modifiers = "i";
let re = new RegExp(pattern, modifiers);
console.log(re.test("Hello, World!")); // true
// 动态改变模式
pattern = "word";
re = new RegExp(pattern, modifiers);
console.log(re.test("Hello, World!")); // false
3.关于正则表达式的方法
我觉得学正则很重要的一个点就是要把方法给熟悉下(反正我是的哈),不然就算你能看懂正则要干什么,但是方法结果返回的是什么你也是白搭的。
关于正则表达式的方法主要分为两类可以,一个是正则使用的,一个是字符串使用的。
3.1 正则的方法
正则的方法主要有regObj.test
,regObj.exec
及regObj.compile
3.1.1 test
test方法就比较简单的,该方法用来测试某个字符串是否与正则匹配,匹配就返回true
,否则返回false
。
const str = "Hello, World!";
const re = /hello/i;
const result = re.test(str);
console.log(result); // false
在上面的代码中,我们定义了一个正则表达式/hello/i,它表示匹配字符串中的hello,不区分大小写。我们使用test()
方法来判断字符串"Hello, World!"是否与正则表达式匹配,最后输出结果为true
。
注意,test()方法只返回一个布尔值,表示字符串是否与正则表达式匹配,而不返回具体的匹配结果。它是正则表达式的基本方法之一,常用于判断一个字符串是否符合特定的模式。
同时,每次调用test()
方法时,正则表达式的lastIndex
属性会被重置为零,以避免在连续调用中出现意外的匹配位置。
3.1.2 compile
我看了很多博客说有这个方法。摘抄mdn上的
已弃用: 不再推荐使用该特性。虽然一些浏览器仍然支持它,但也许已从相关的 web 标准中移除,也许正准备移除或出于兼容性而保留。请尽量不要使用该特性,并更新现有的代码;参见本页面底部的兼容性表格以指导你作出决定。请注意,该特性随时可能无法正常工作。
属于是已弃用了的
3.1.3 exec
这个exec方法就是常用又非常重要的方法了。
如果匹配失败,exec() 方法返回 null,并将正则表达式的 lastIndex 重置为 0。
如果匹配成功,exec() 方法返回一个数组,并更新正则表达式对象的 lastIndex 属性。完全匹配成功的文本将作为返回数组的第一项,从第二项起,后续每项都对应一个匹配的捕获组。数组还具有以下额外的属性:
index
匹配到的字符位于原始字符串的基于 0 的索引值。
input
匹配的原始字符串。
groups
一个命名捕获组对象,其键是名称,值是捕获组。若没有定义命名捕获组,则 groups 的值为 undefined。参阅捕获组以了解更多信息。
indices 可选
此属性仅在设置了 d 标志位时存在。它是一个数组,其中每一个元素表示一个子字符串的边界。每个子字符串匹配本身就是一个数组,其中第一个元素表示起始索引,第二个元素表示结束索引。
/ab/.exec('abcab')
//['ab', index: 0, input: 'abcab', groups: undefined]
/ab/.exec('aca')
//null
关于如果匹配成功,exec()
方法返回一个数组,并更新正则表达式对象的 lastIndex
属性这句话的理解
const regex1 = RegExp('foo', 'g');
const str1 = 'table football, foosball';
let array1;
while ((array1 = regex1.exec(str1)) !== null) {
console.log(array1,`Next starts at ${regex1.lastIndex}.`);
// Expected output:['foo', index: 6, input: 'table football, foosball', groups: undefined] 'Next starts at 9.'
// Expected output: ['foo', index: 16, input: 'table football, foosball', groups: undefined] 'Next starts at 19.'
}
可以看到正则表达式对象的 lastIndex
属性和匹配成功后返回的数组的index
属性一般是不同的。这里返回的数组第三个参数提到了命名捕获组对象,我们就要引出一个捕获组对象了。
捕获组对象
什么是捕获组对象呢?
正则表达式的捕获组是指被圆括号包围的部分表达式,用于分组和捕获匹配的子字符串。捕获组允许您从匹配的字符串中提取特定部分或将整个匹配项分割为更小的子部分。
看着这注释也抽象哈,直接上代码
const pattern = /(\w+)\s(\w+)/;
const str = 'Hello World';
const result = pattern.exec(str);
console.log(result); //['Hello World', 'Hello', 'World', index: 0, input: 'Hello World', groups: undefined]
匹配的正则的意思是匹配已空格为分割的前面是一个或多个单词字符,后面也是一个或多个单词字符的字符串。如果没有()
,即没有捕获组的话,结果应该是[‘Hello World’, index: 0, input: ‘Hello World’, groups: undefined]。但是有了捕获组后发现数组多了两项,‘hello’和’world’。所以我觉得捕获组就是从你匹配到的整个字符串里可以提取某些小的部分,有多少个匹配组就有多少个提取的小模块。
其实下面还有特别的具名捕获组对象和非捕获组。
具名捕获组对象
具名捕获组对象的语法是
(?x) //匹配"x"并将其存储在返回的匹配项的 groups 属性中,该属性位于指定的名称下。
有什么作用呢?上面我们举例的捕获组对象返回的数组中有两个捕获组对象,但是想要在数组中知道某一个捕获组匹配到的是身份证的年月日呢还是学号呢(几个例子),所以我们就可以使用具名捕获组对象给它一个标识,上面中的Name存储在返回的匹配项的 groups
属性中,该属性位于指定的名称下,这样的话我们就可以更方便的拿到想要的数据了。
const pattern = /(?<firstName>\w+)\s(?<lastName>\w+)/;
const str = 'John Doe';
const result = pattern.exec(str);
console.log(result);
console.log(result[0]);
console.log(result[1]);
console.log(result[2]);
console.log(result.groups);
console.log(result.groups.firstName);
console.log(result.groups.lastName);
运行结果:
可以看到返回的匹配数组中gropus有值了,我们就可以通过groups来取值了
非捕获组对象
正则表达式中的非捕获组(Non-capturing group)是用来匹配模式但不捕获匹配结果的一种语法结构。非捕获组有助于优化正则表达式的性能,并且在不需要捕获结果时可以减少内存消耗。
在正则表达式的模式中,使用 (?:...)
的语法表示一个非捕获组。非捕获组中的子表达式会被按照正常规则匹配,但匹配结果不会被捕获到结果数组中。
const pattern = /(?:\d{3})-(?<center>\d{3})-(\d{4})/;
const str = '123-456-7890';
const result = pattern.exec(str);
console.log(result)
运行截图:
可以看到有三个捕获组对象,但是第一个是非捕获组对象,所以在返回的数组是没有它的匹配结果的。
3.2 String类型的对象的正则相关的方法
3.2.1 search()
它用于在字符串中查找指定的子字符串,并返回第一次匹配的索引位置。如果找不到匹配的子字符串,search
方法将返回 -1。
const str = 'Hello, world!';
const pattern = /world/;
const index = str.search(pattern);
console.log(index); // 7
需要注意的是,search
方法只会返回第一次匹配的索引。如果需要查找所有匹配项的索引,可以使用正则表达式的 g
修饰符,并结合 RegExp 的 exec
方法进行循环匹配。
如果传递给 search
方法的参数不是一个正则表达式对象,而是普通字符串,search
方法内部会自动将其转换为一个临时的正则表达式对象进行匹配。
const str = 'Hello, world!';
const searchStr = 'world';
const index = str.search(searchStr);
console.log(index); // 7
在上述示例中,我们将字符串 ‘world’ 作为参数传递给了 search
方法,而不是一个正则表达式对象。然而,search
方法会隐式将该字符串转换为临时的正则表达式对象,相当于使用 /world/ 这样的正则表达式进行匹配,然后返回第一个匹配的索引位置,这里是 7。
这个隐式的转换使得我们可以使用字符串来进行简单的文本搜索操作,无需显式创建正则表达式对象。
需要注意的是,字符串作为参数传递给 search
方法时,它将被视为一个普通字符串而不是一个正则表达式模式。如果需要进行更复杂的模式匹配操作,可以创建一个正则表达式对象,并使用相应的正则表达式语法。
3.2.2 replace()
replace
方法是 JavaScript 字符串对象的原生方法之一,用于替换字符串中的文本。它接受一个模式(可以是一个正则表达式或者字符串)和一个替换字符串作为参数,并返回一个新的字符串,其中替换了符合模式的文本。
replace
方法的语法如下:
string.replace(regexp|substr, newSubStr|function)
其中,string
是要进行替换操作的目标字符串,regexp|substr
是要匹配或查找的模式,newSubStr|function
是用于替换匹配文本的新字符串或者用于生成新字符串的函数。
以下是几个使用 replace
方法的示例:
- 替换指定字符串的所有匹配项:
const str = 'Hello, world!';
const newStr = str.replace('world', 'universe');
console.log(newStr); // "Hello, universe!"
在上述示例中,我们使用 replace
方法将目标字符串 'Hello, world!'
中的 'world'
替换为 'universe'
。结果将返回新字符串 'Hello, universe!'
。
- 使用正则表达式进行替换:
const str = 'Hello, world!';
const newStr = str.replace(/o/g, '0');
console.log(newStr); // "Hell0, w0rld!"
在上述示例中,我们使用正则表达式 /o/g
匹配目标字符串中的所有字母 'o'
,并将其替换为数字 '0'
。结果将返回新字符串 'Hell0, w0rld!'
。
- 使用函数生成替换字符串:
const str = 'Hello, world!';
const newStr = str.replace(/(\w+)\s(\w+)/, function(match, p1, p2) {
return p2 + ', ' + p1;
});
console.log(newStr); // "world, Hello!"
在上述示例中,我们使用正则表达式 (\w+)\s(\w+)
匹配目标字符串中的两个单词,并使用一个函数来生成替换后的字符串。在函数中,match
参数表示整个匹配到的文本,p1
和 p2
则分别表示第一个和第二个括号捕获的子字符串。我们返回了一个新的字符串,将两个单词的顺序进行了颠倒。结果将返回新字符串 'world, Hello!'
。
需要注意的是,replace
方法并不会修改原始字符串,而是返回一个新的替换后的字符串。如果模式没有匹配到任何文本,原始字符串将保持不变。
3.2.3 split()
split
方法是 JavaScript 字符串对象的原生方法之一,用于将字符串拆分为子字符串数组。它接受一个分隔符作为参数,并根据该分隔符将字符串分割成多个子字符串。
split
方法的语法如下:
string.split(separator, limit)
其中,string
是要进行拆分操作的目标字符串,separator
是用于指定分隔符的字符串或正则表达式。可选的 limit
参数用于限制拆分后的子字符串数量。
以下是几个使用 split
方法的示例:
- 使用普通的字符串分隔符:
const str = 'Hello,world,how,are,you?';
const arr = str.split(',');
console.log(arr); // ["Hello", "world", "how", "are", "you?"]
在上述示例中,我们使用逗号作为分隔符,将目标字符串 'Hello,world,how,are,you?'
分割成了一个字符串数组 ["Hello", "world", "how", "are", "you?"]
。
- 使用正则表达式分隔符:
const str = 'Hello world!';
const arr = str.split(/\s+/);
console.log(arr); // ["Hello", "world!"]
在上述示例中,我们使用正则表达式 /\\s+/
作为分隔符,它匹配一个或多个连续的空白字符。这样,目标字符串 'Hello world!'
就被拆分成了一个字符串数组 ["Hello", "world!"]
。
- 限制拆分后的子字符串数量:
const str = 'apple,banana,grape,orange,strawberry';
const arr = str.split(',', 3);
console.log(arr); // ["apple", "banana", "grape"]
在上述示例中,我们使用逗号作为分隔符,并将 limit
参数设置为 3
。这意味着最多只会拆分出 3 个子字符串。结果将返回一个数组 ["apple", "banana", "grape"]
。
需要注意的是,split
方法不会修改原始字符串,而是返回一个新的数组。如果分隔符未能在字符串中匹配到任何内容,split
方法将返回只包含原始字符串的数组。
const str = 'apple,banana,grape,orange,strawberry';
const arr = str.split(',,', 3);
console.log(arr); // ['apple,banana,grape,orange,strawberry']
上面的示例中,str 是 ‘apple,banana,grape,orange,strawberry’,而 split 方法的参数是 ‘,’,我们将使用该参数将字符串分割为最多 3 个子字符串。
然而,‘,’ 并不是一个合法的分隔符,它表示两个逗号连续出现的情况。在 split 方法中,连续的分隔符被视为一个整体。因此,当我们尝试使用 ‘,’ 进行拆分时,它将无法在字符串中找到这样的连续逗号。
split 方法将返回一个包含原始字符串的数组,因为分隔符在目标字符串中没有匹配项。
所以,根据给定的示例,arr 的结果将是 [‘apple,banana,grape,orange,strawberry’],一个包含原始字符串的数组。
请注意,如果要使用连续逗号作为分隔符,应该在字符串中确实存在这样的连续逗号,例如 ‘apple,banana,grape,orange,strawberry’。然后,split 方法将正确地将字符串拆分为多个子字符串,并限制拆分后的子字符串数量为 3。
match
方法是 JavaScript 字符串对象的原生方法之一,用于从字符串中提取与指定模式匹配的内容,并返回一个匹配结果数组或者 null
。
3.2.4 match()
match
方法接受一个正则表达式作为参数,然后在字符串中寻找与该正则表达式匹配的子字符串。该方法接受一个正则作为参数,用来匹配一个字符串,它的输出结果在不是全局匹配的情况下和exec
方法的结果一致即一个数组并带有额外的属性,如果采用g
全局匹配,则不返回任何和其被匹配字符串相关的信息,只返回匹配的结果。
以下是 match
方法的语法:
string.match(regexp)
其中,string
是要进行匹配操作的目标字符串,regexp
是一个正则表达式,用于指定匹配模式。
以下是几个使用 match
方法的示例:
- 提取所有匹配的子字符串:
const str = 'Hello, how are you today?';
const result = str.match(/[a-z]+/gi);
console.log(result); // ["Hello", "how", "are", "you", "today"]
在上述示例中,我们使用正则表达式 /[a-z]+/gi
,该正则表达式匹配字符串中的所有连续小写字母组合。match
方法将返回一个包含所有匹配项的数组 ["Hello", "how", "are", "you", "today"]
。
- 检查是否有匹配项:
const str = 'Hello, how are you today?';
const result = str.match(/how/);
console.log(result); //['how', index: 7, input: 'Hello, how are you today?', groups: undefined]
在上述示例中,我们使用正则表达式 /how/
,它匹配字符串中的子字符串 'how'
。由于字符串中存在这样的匹配项,match
方法将返回一个包含该匹配项的数组。
如果在字符串中没有找到匹配项,match
方法将返回 null
。
需要注意的是,如果正则表达式使用了全局标志 (g
),match
方法将返回所有匹配项的数组。如果没有使用全局标志,只会返回第一个匹配项的数组。
3.2.5 matchAll()
matchAll
是 JavaScript 字符串对象的原生方法之一,它用于在字符串中执行全局匹配,并返回一个迭代器(Iterator),该迭代器包含与指定正则表达式匹配的所有结果。
matchAll
方法接受一个正则表达式作为参数,并在字符串中查找与该正则表达式匹配的所有子字符串。
以下是 matchAll
方法的语法:
string.matchAll(regexp)
其中,string
是要进行匹配操作的目标字符串,regexp
是一个正则表达式,用于指定匹配模式。
以下是一个使用 matchAll
方法的示例:
const str = 'Hello, how are you today?';
const regexp = /[a-z]+/gi;
const result = str.matchAll(regexp);
for (const match of result) {
console.log(match);
}
运行结果:
在上述示例中,我们使用正则表达式 /[a-z]+/gi
,该正则表达式匹配字符串中的所有连续小写字母组合。matchAll
方法返回一个迭代器对象,它包含所有与正则表达式匹配的子字符串。
需要注意的是,matchAll
方法是在 ECMAScript 2020 中引入的,如果您使用的是较旧的 JavaScript 版本,可能不支持该方法。可以使用 Polyfill 或者使用其他方法(例如 match
方法的循环)来实现类似的功能。