正则表达式学习

什么是正则表达式

正则表达式,常常缩写为 “regex” 或 “regexp”,是帮助程序员匹配、搜索和替换文本的模式。

正则表达式的测试方法

  1. regex.test('string') 返回 boolean 类型的值,即truefalse
const testStr = 'hello world'
const regex = /hello/
const result = regex.test(testStr)
console.log(result) // true
  1. 'string'.match(regex)
  • 用于提取具体的匹配项
  • 返回所有匹配项的字符串数组
// 1. 用于提取具体的匹配项
const testStr = 'hello world'
const regex = /hello/
const result = testStr.match(regex) // ['hello', index: 0, input: 'hello world', groups: undefined]

// 2. 返回所有匹配项的字符串数组
// 注意 ourRegex 增加了 g flag 用于多次提取匹配项
let testStr2 = "Repeat, Repeat, Repeat";
let ourRegex = /Repeat/g;
let ourRegex2 = /Repeat/
testStr2.match(ourRegex) // ['Repeat', index: 0, input: 'Repeat, Repeat, Repeat', groups: undefined]
testStr2.match(ourRegex) // ['Repeat', 'Repeat', 'Repeat']

正则表达式用法

操作符

此操作符匹配操作符前面或者操作符后面的字符。具体写法即/regex1|regex2/

const testStr = 'James has a pet cat, you have a pet dog, i have a pet bird'
const regex = /cat|dog/
const result = regex.test(testStr) // true
// 匹配是否包含字符cat 或者字符 dog

忽略大小写,通过标志(flag) i进行匹配

i 此 flag 可以忽略匹配的字符串的大小写,具体写法:/regexPattern/i

const testStr = 'FreECodeCamp'
const testStr2 = 'FREECODECAMP'
const regex = /freecodecamp/i
const result = regex.test(testStr) // true
const result2 = regex.test(testStr) // true

全局匹配, 使用标志 g

g 此 flag 用于多次搜寻或者提取模式匹配

// 从twinkleStar 中提取所有的twinkle
let twinkleStar = "Twinkle, twinkle, little star";
let starRegex = /twinkle/gi;
let result = twinkleStar.match(starRegex);  // ['Twinkle', 'twinkle']

通配符 . 匹配任何内容

题目:完成正则表达式 unRegex 以匹配字符串 runsunfunpunnunbun。 正则表达式中应该使用通配符

let exampleStr = "Let's have fun with regular expressions!";
let unRegex = /.un/; // 修改这一行
let result = unRegex.test(exampleStr);
console.log(result) // true
// unRegex 可以匹配任何 un 相关的字符串

单个字符与多种可能性的匹配

通过把字符放入[]之间来定义一组需要匹配的字符串

let quoteSample = "Beware of bugs in the above code; I have only proved it correct, not tried it.";
let vowelRegex = /[aeiou]/gi;
let result = quoteSample.match(vowelRegex);
// result 的值将是所有 a e i o u 字符串的集合

匹配字母表中的字母

可以使用 - 连字符 来定义要匹配的字符范围 例如,要匹配小写字母 a 到 z, 你可以使用[a-z]

let quoteSample = "The quick brown fox jumps over the lazy dog.";
let alphabetRegex = /[a-z]/gi; // 修改这一行
let result = quoteSample.match(alphabetRegex); // 修改这一行
console.log(result)

// 或者
let catStr = "cat";
let batStr = "bat";
let matStr = "mat";
let bgRegex = /[a-e]at/;
catStr.match(bgRegex);
batStr.match(bgRegex);
matStr.match(bgRegex);

匹配字母表中的数字和字母

let jennyStr = "Jenny8675309";
let myRegex = /[a-z0-9]/ig;
let result = jennyStr.match(myRegex)

匹配单个未指定的字符

使用 ^ 字符来创建一个不想匹配的字符集, 即否定字符集,例如,可以使用/[^aeiou]/gi来匹配所有非元音的字符。

// 创建一个匹配所有非数字或元音字符的正则表达式。 请记得在正则表达式中包含恰当的标志
// myRegex 或者 myRegex2的写法都可以
let quoteSample = "3 blind mice.";
let myRegex = /[^aeiou^0-9]/gi
let myRegex2 = /[^aeiou|^0-9]/
let result = quoteSample.match(myRegex)
console.log(result) // [' ', 'b', 'l', 'n', 'd', ' ', 'm', 'c', '.']

匹配出现 1 次或者多次的字符

使用 + 符号来检查是否匹配

let difficultSpelling = "Mississippi";
let myRegex = /s+/g;
let result = difficultSpelling.match(myRegex);
console.log(result) // ['ss', 'ss']

匹配 0 次或者多次的字符

使用* 符号来检查是否匹配

let soccerWord = "gooooooooal!";
let gPhrase = "gut feeling";
let oPhrase = "over the moon";
let goRegex = /go*/;
soccerWord.match(goRegex); // ['goooooooo', index: 0, input: 'gooooooooal!', groups: undefined]
gPhrase.match(goRegex); // ['g', index: 0, input: 'gut feeling', groups: undefined]
oPhrase.match(goRegex); // null


let chewieQuote = "Aaaaaaaaaaaaaaaarrrgh!";
let chewieRegex = /Aa*/; // Change this line
let result = chewieQuote.match(chewieRegex);

惰性匹配来查找字符

在正则表达式中,贪婪(greedy) 匹配会匹配到符合正则表达式匹配模式的字符串的 最长可能部分,并将其作为匹配项返回。另一种方案称为 懒惰(lazy) 匹配,它会匹配到满足正则表达式的字符串的最小可能部分, 懒惰匹配使用 ? 匹配符进行懒惰匹配

let reg = /t[a-z]*?i/
'titanic'.match(reg) // ['ti', index: 0, input: 'titanic', groups: undefined]

// 修复正则表达式 /<.*>/,让它返回 HTML 标签 <h1>,而不是文本 "<h1>Winter is coming</h1>"。 请记得在正则表达式中使用通配符 . 来匹配任意字符。
let text = "<h1>Winter is coming</h1>";
let myRegex = /<.*?>/;
let result = text.match(myRegex);
console.log(result)

匹配字符串的开头

^ 来匹配字符串的开头,注意与第 9 条的区别

let rickyAndCal = "Cal and Ricky both like racing.";
let calRegex = /^Cal/;
let result = calRegex.test(rickyAndCal); // true

匹配字符串的末尾

$ 来搜寻字符串的结尾

let caboose = "The last car on a train is the caboose";
let lastRegex = /caboose$/;
let result = lastRegex.test(caboose); // true

匹配所有的字母和数字

可以使用元字符 \w 来进行匹配,与 \w 最接近的是 [a-zA-Z0-9_] 。 类似 \w这种元字符的索耶也被称为短语元字符

let quoteSample = "The five boxing wizards jump quickly.";
let alphabetRegexV2 = /\w/g;
let result = quoteSample.match(alphabetRegexV2).length;

匹配除了数字和字母以外的所有字符

可以使用 \W 短语元字符, 注意此处的W是大写,刚好与 \w 相反。

let quoteSample = "The five boxing wizards jump quickly.";
let nonAlphabetRegex = /\W/g;
let result = quoteSample.match(nonAlphabetRegex).length;

匹配所有数字

可以使用 \d 短语元字符。其中 \d 等同于 [0-9]

let movieName = "2001: A Space Odyssey";
let numRegex = /\d/g;
// let numRegex = /[0-9]/g // 也是可以的
let result = movieName.match(numRegex).length; // 4

匹配所有非数字

可以使用 \D 短语元字符,注意 D 为大写,\D 等同于 [^0-9]

let movieName = "2001: A Space Odyssey";
let noNumRegex = /\D/g;
// let noNumRegex = /[^0-9]/g
let result = movieName.match(noNumRegex).length;

练习题

  1. 用户名只能是数字字母字符。
  2. 用户名中的数字必须在最后。 数字可以有零个或多个。 用户名不能以数字开头。
  3. 用户名字母可以是小写字母和大写字母。
  4. 用户名长度必须至少为两个字符。 两位用户名只能使用字母
let username = "JackOfAllTrades";
let userCheck = /^[a-z][a-z]+\d*$|^[a-z]\d\d+$/gi
let result = userCheck.test(username);

匹配空白字符串

可以使用 \s 搜寻空格,其中 s 是小写。 此匹配模式将匹配空格、回车符、制表符、换页符和换行符。 可以认为这类似于元字符 [ \r\t\f\n\v]

// 找出sample多个空白字符
let sample = "Whitespace is important in separating words";
let countWhiteSpace = /\s/g;
let result = sample.match(countWhiteSpace);

匹配非空白字符

使用 \S 搜寻非空白字符,其中 S 是大写。 此匹配模式将不匹配空格、回车符、制表符、换页符和换行符。 可以认为这类似于元字符 [^ \r\t\f\n\v]

let sample = "Whitespace is important in separating words";
let countNonWhiteSpace = /\S/g; // 修改这一行
let result = sample.match(countNonWhiteSpace)

指定匹配的上限和下限

可以使用数量说明符,指定匹配模式的上下限。数量说明符与花括号( {} ) 一起使用。可以在花括号之间放两个数字,这两个数字代表匹配模式的上限和下限。 如果匹配 h 字符 3 到 6 次就可以写为 h{3, 6},其中,3 代表匹配模式的下限即最少几个,6 代表匹配模式的上限即最多几个 题目: 修改正则表达式 ohRegex 以匹配出现 3 到 6 次字母 h 的字符串 Oh no

let ohStr = "Ohhh no";
let ohRegex = /Oh{3,6}\s*no/;
let result = ohRegex.test(ohStr);

只指定匹配的下限

使用数量说明符, 可以写为{3,} 即可。不需要指定上限即可匹配 3+个字符 题目:匹配包含四个或更多字母 z 的单词 Hazzah

let haStr = "Hazzzzah";
let haRegex = /Haz{4,}ah/;
let result = haRegex.test(haStr);

指定匹配的确切数量

使用数量说明符,花括号中写具体的数量即可。例如,要只匹配字母 a 出现 3 次的单词 hah,正则表达式应为/ha{3}h/。 题目:修改正则表达式 timRegex,以匹配仅有四个字母 m 的单词 Timber。

let timStr = "Timmmmber";
let timRegex = /Tim{4}ber/;
let result = timRegex.test(timStr);

检查全部或者无

当想要搜寻的匹配模式可能有不确定是否存在的部分,但是还想要进行匹配,那么可以选择使用问号 ? 指定可能存在的元素。 ? 可以检查前面的零个或者一个元素。理解为 ? 前面的一个元素是可选的。 例如,美式英语和英式英语略有不同,可以使用问号来匹配两种拼写

let american = "color";
let british = "colour";
let rainbowRegex= /colou?r/; // 可以匹配u,也可以不匹配u
rainbowRegex.test(american); // true
rainbowRegex.test(british) // true

let favWord = "favorite";
let favRegex = /favou?rite/;
let result = favRegex.test(favWord);

正向先行断言和负向先行断言

正则表达式的先行断言(lookahead)和后行断言(lookbehind) | 菜鸟教程open in new window 题目:在正则表达式 pwRegex 中使用先行断言以匹配大于 5 个字符且有两个连续数字的密码

// 答案一
let sampleWord = "astronaut";
let pwRegex =  /(?=\w{6})(?=\w*\d{2})/;
let result = pwRegex.test(sampleWord);

// 答案二
let sampleWord = "astronaut";
let pwRegex = /(?=\w{6,})(?=\w*\d\d+)/;
let result = pwRegex.test(sampleWord);

检查混合字符串组

题目:完善正则表达式,使其以区分大小写的方式检查 Franklin RooseveltEleanor Roosevelt 的名字,并且应该忽略 middle names

// 答案一
let myString = "Eleanor Roosevelt";
let myRegex = /(Franklin|Eleanor).*Roosevelt/;
let result = myRegex.test(myString);
// 答案二
let myString = "Eleanor Roosevelt";
let myRegex = /(Eleanor|Franklin)\s*.*\s* Roosevelt/;
let result = myRegex.test(myString);