細雨

The Magic of Regex

1.提取字符串中所有 4 位连续数字

给定一段字符串,找到所有不重复的连续的 4 个数字组成的子字符串,例:123456 -> ['1234', '2345', '3456']

// 输入
"abc1234d567890123456efg345hi777777j890"

// 输出
['1234', '5678', '6789', '7890', '8901', '9012', '0123', '2345', '3456', '7777'];
解:
// 法一
[...'abc1234d567890123456efg345hi777777j890'.matchAll(/(?=(\d{4})(?<!\1.+))/g)].map((e) => e.pop());

// 法二
[...new Set([...'abc1234d567890123456efg345hi777777j890'.matchAll(/(?=(\d{4}))/g)].map((e) => e.pop()))];

2.Reverse case

const input = 'Hello world!';

const reverseCase = (txt) => {
// write your code here
};

console.log(reverseCase(input)); // "hELLO wORLD!"
解:
'Hello world!'.replace(/[a-z]/gi, (c) => String.fromCharCode(c.charCodeAt() ^ 32));

3.任务队列

setTimeout(() => {
console.log(1);
}, 0);
new Promise((resolve) => {
resolve();
console.log(2);
}).then(() => {
console.log(3);
});
const foo = async () => {
console.log(4);
await bar();
console.log(5);
};
const bar = () => {
console.log(6);
};
foo();
console.log(7);
解:
2467351

4.转换金额

const convertToPrice = (num: string) => {
// write your code here
};

console.log(convertToPrice(12)); // $12.00
console.log(convertToPrice(1687001)); // $1,687,001.00
console.log(convertToPrice(136.456)); // $136.45
console.log(convertToPrice(-160164.2)); // -$160,164.20
解:
const convertToPrice = (num: string) => {
// write your code here
const formatNum: string = num.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,');
return '$' + formatNum;
};

5.三角形

// write your code here
console.log('*********'.replace(...));
// *********
// ********
// *******
// ******
// *****
// ****
// ***
// **
// *
解:
console.log('*********'.replace(/(?!^)(?=(\*+))/g, '$1\n'))

6.获取字符串最后一个数字

// 取出 `购买1个` 中的数字 `1`
const str = '对不起,【新客专享!19.9 元 4 件】润百颜水润次抛 2 支+美白次抛 1 支+屏障调理面膜 1 片全活动周期内最多只能购买 1 个。';
解:
str.match(/\d+/g).pop()

7.匹配所有双引号外的文字

const input = 'Hello my "name" is "John Smith Doe", nice "to meet" you.';

input.match(/开始你的表演/g); // ['Hello my ', ' is ', ', nice ', ' you.']
解:
/(?:"[^"]+"\K)?[^"]+/g;

8.匹配由小写字母组成的合法的减法表达式,要求等式三个部分齐全,且“被减数”必须是“减数”的子串

匹配
aa-a=a
abc-b=ac
aaaa-aa=aa
aabb-ab=ab
aabb-aab=b
aabbcc-aa=bbcc
aaaabbbb-ab=aaabbb
ababab-b=abaab
ababab-b=aabab
ababab-b=ababa

不匹配:
aa-a=aa
abc-b=a
aaaa-aa=aaa
aabb-aab=ab
a-a=
aa-=aa
aaaabbbb-ab=aaaabbb
ababab-aab=bbab
abcd-ac=bd
++-+=+

解:
/^(?=.+-.+=.+)(\w*)(\w*)(\w*)-\2=\1\3$/gm;

9.匹配由两种不同字符组成的字符串,前者重复次数与后者相同

匹配:
ab
aabb
aaabbb
cd
ccccdddd
eeeeeeefffffff
++++++------
[[[[[]]]]]
(((())))

不匹配:
abc
a
aab
abb
abab
aaaabbb
aabbbb
aabbaabb
cdd
abc
解:
/^(?=(.)\1*((?!\1).))(\1(?3)?\2)$/gm;

10.判断包含 ABCD 中的任意两种, 且仅有两种

通过:
12A345678B
777C542AA12
AB
CDC
BD12
123AB456
AAABBB
1A2A3A4C5C1C1

不通过:
ABC
ABCD
123ABC
12345A123
123
解:
/^(?=.*([ABCD]).*(?!\1)([ABCD]))(?!.*(?!\1|\2)[ABCD]).*/gm;

11.判断只包含张三、李四、王五和赵六中的两种

通过:
我认识张三和李四
张三和王五在玩游戏
李四和赵六今天没来
张三先到,赵六后到的
王五:“张三是我的好朋友”
张三:“我叫张三,王五是我的好朋友”
张三丰:“我叫张三,王五六是我的好朋友”

不通过:
今天张三请假了
张三、李四和王五在玩游戏
昨天张三、李四、王五和赵六在一起打了麻将
我认识张四和李三
张三:“我叫张三”
今天没有人请假
解:
/^(?=((?!(张三|李四|王五|赵六)).)*((?2))(?:(?1)|\3)*(?!\3)((?2)))(?!(?:(?1)|\3|\4)*(?!\3|\4)(?2)).*$/gm;

12.匹配一行文字中存在出现过两次且仅出现过两次的数字

匹配:
1 1
1 1 2
1 1 2 2
1 2 3 1
11 11
10 11 12 100 10
10 20 30 20 30
10 20 30 20 30 30
100 200 300 404 500 200 300 300
1 1 1 2 2

不匹配:
1
11
1 1 1
1 2 3
1 2 3 123
1 2 3 1 1
10 11 12 100 100 100 100
10 20 30 20 30 20 30
10 20 30 20 30 30 20
100 200 300 404 500 200 300 300 200
解:
// PCRE
/^
(?*.*?\b(\d+)\b) # 非元组断言捕获数字进入组1,后续匹配失败后确保可以回溯到断言组内重新捕获组1
(?>.*?\b\1\b){2} # 元组匹配该数字出现两次重复,匹配失败后确保不会回溯到组内,防止.*?中出现组1内容
(?!.*\b\1\b).* # 后续不再出现组1中的数字
$/gmx

// JS
/^.*(\b\d+\b)(?<!\b\1\b.*\b\1\b)(?=.*\b\1\b)(?!.*\b\1\b.*\b\1\b).*$/gm;

13.找到在括号外的所有字符串

(题目要求:找到所有在)最外层配对的括号外(的所有字符串,)注意括号有可能(会((嵌套))哦!) :) (async () => { await console.log(1); })()) 加油 ()()(())():((1)((((((2)((3)))))))最好匹配连续,(且没有多余的分组())() 2 * (1 + 3) = 8(eight) :( 你成功了吗?(yes) no
解:
/(\((?:[^()]|(?1))*+\))(*SKIP)(*F)|.+?(?=$|(?1))/gm;

14.在 JavaScript 中,关键词 void 是什么?

A.类型;
B.方法;
C.运算符;
D.声明关键词;
解:
C

15.尽可能短的代码实现 FizzBuzz

尽可能短的代码实现 FizzBuzz

解:
[...Array(100)].map((_, i) => (++i % 3 ? '' : 'fizz') + (i % 5 ? '' : 'buzz') || i);
for (a = [], i = 0; i < 100; ) (a[i] = (++i % 3 ? '' : 'Fizz') + (i % 5 ? '' : 'Buzz') || i), a;

16.try catch

以下代码输出什么

const foo = () => {
try {
new Error('nope');
return 1;
} catch (ex) {
return 2;
} finally {
return 3;
}
};

const bar = () =>
new Promise((resolve, reject) => {
try {
new Error('nope');
resolve(1);
} catch (ex) {
reject(2);
} finally {
resolve(3);
}
});

console.log(foo());
console.log(await bar());
解:
3
1

17.变量提升

以下代码输出什么

if (true) {
foo();

function foo() {
console.log(1);
}

foo = 2;

function foo() {
console.log(3);
}

foo = 4;

console.log(foo);
}
console.log(foo);
解:
3
4
2

18.严格模式

以下代码输出什么

function func1() {
arguments[0]++;
return arguments[0];
}

function func2(a, b) {
arguments[0]++;
return a;
}

function func3(a, b = 0) {
arguments[0]++;
return a;
}
console.log(func3(func2(func1(0))));
解:
// 当非严格模式中的函数有包含剩余参数、默认参数和解构赋值,那么arguments对象中的值不会跟踪参数的值(反之亦然)。
2

19.匹配由第一个遇到的可选的“开始”到第一个遇到的可选的“结束”之间的字符串

// 题目要求:匹配由第一个遇到的可选的“开始”到第一个遇到的可选的“结束”之间的字符串。

123456789
123456结束789
123开始456789
123开始456结束789
123结束456开始789
1开始23开始456结束789
123开始456结束78结束9
123456结束78结束9
12结束3开始456结束78开始9
12开始3开始456开始78开始9
解:
// js
/(?<=开始|^(?!(?:(?!结束).)*开始))(?<!结束.*)(?:(?!结束).)+/gm
// PCRE
/(?:^|\G)(?>(?:(?!结束).)*?开始\K|^)(?:(?!结束).)+/gm

20.方括号内数字累加

add[1] + 1 // 2
add[1][2][3] + 4 // 10
add[10][-5][3][100] *2 // 216
+add[1][2][3][4][5] // 15
解:
const makeProxy = (total = 0) =>
new Proxy([], {
get(_, prop) {
if (prop === Symbol.toPrimitive) return () => total;
return makeProxy(total + Number(prop));
},
});
const add = makeProxy();

21.找到出现一次和多次的字符并标记

编写一个函数,接收一个字符串后,对于只出现一次的字符标记为(,出现多次的标记为),并组成一个新的字符串返回。 注:判断重复时忽略大小写。

示例 1:

输入:"din"
输出:"((("

示例 2:

输入:"recede"
输出:"()()()"

示例 3:

输入:"(( @"
输出:"))(("
解:
const rep = (text) => text.replace(/(.)(?=.*\1|(?<=\1.+))|./g, (_, g) => '()'[+!!g]);
rep('din'); // "((("
rep('recede'); // "()()()"
rep('(( @'); // "))(("

22.生成包含 1-100 的数组,但不包含 3 的倍数

生成包含 1-100 的数组,但不包含 3 的倍数
要求 1:一行代码、禁止字面量(出现手动定义 1、2、4、5...的行为)
要求 2:不使用 Array 和 String 相关的任何方法,包括原型链以及构造方法
要求 3:禁止声明变量(var、let、const 以及全局变量)
要求 4:代码中禁止出现等于号"="
解:
Object.values(
(function (f, i, r) {
return f(f, i, r);
})(
function (f, i, r) {
return i > 100 ? r : f(f, i + 1, i % 3 ? { ...r, [i]: i } : r);
},
1,
{}
)
);
[
...(function* () {
while (arguments[0]++ < 100) if (arguments[0] % 3) yield arguments[0];
})(0),
];

23.生成 1-100 的 FizzBuzz 数组

生成1-100的FizzBuzz数组
条件1:禁止出现字面量(直接定义[1, 2, "Fizz", ...])
条件2:禁止出现任何值比较和条件语句(if、while、switch、三元表达式、==、!=、&&、||等)
条件3:一行代码
解:
Array.from({ length: 100 }, (_, i) => [++i, 'Fizz', 'Buzz', 'FizzBuzz'][!(i % 3) + !(i % 5) * 2]);

24.获取函数名

const getCurrentFunctionName = () => {
// 开始你的表演
};

const foo = () => {
console.log(getCurrentFunctionName());
};

function bar() {
console.log(getCurrentFunctionName());
}

foo();
bar();
解:
const getCurrentFunctionName = () => /.*at ([\w$]+)/s[Symbol.match](new Error().stack)[1];

25.找到所有成对双引号内的单引号

The quick "bro'wn fox'" jumps' over "the la'zy" do'g. The "qui'ck" bro'wn fox ' ju"mps' over the'"lazy"dog'.
解:
// https://regex101.com/r/hBeSAg/1
/(?>(?!^)\G|").*?(?:"(*SKIP)(*F)|\K'(?=.*"))/gm;

26.在由数字和括号组成的字符串中(括号不对称),找到最内层括号内所有偶数位的数字

(1359)0112(7)10(89)369
123(4567)89876(5432101)234567
016(1359)1369(543)(2123)01234

(123454(1359)01(12(7)10(89)369
12)3(4567)89876(54(32)101)234567
01(2346(1353569)1369(543)(2123)012)34123
解:
// https://regex101.com/r/rCNPnT/1
/(?:\(|(?!^)\G)\d\K\d(?=\d*\))/gm;

27.找到成对的双引号

12"34"56"78"9
解:
// https://regex101.com/r/Xm7USm/1
/"(?:[^\\"\n]|\\.)*"/gm;

28.使用正则表达式分割字符串为数组

// 输入
const csv = '1234567890|ABCDE|""|"01|02|03"|TEST||AT|899';
// 输出
[
'1234567890',
"ABCDE",
'""',
'"01|02|03"',
'TEST',
'',
'AT',
'899'
]
解:
csv.match(/"[^"]*"|^\w*(?=\|)|(?<=\|)\w*/g)

29.对于两位数以上的数字,将其中间的数字用*代替,*与被加密的数字位数相同,但至少存在3个以上

// https://regex101.com/r/1tbZyu/1
// 对于两位数以上的数字,将其中间的数字用*代替,*与被加密的数字位数相同,但至少存在3个以上
12
123
1234
12345
123456
1234567
12345678
123456789
解:
((?<=^.).{0,3}(?=.$))|(?<!^).(?=.+$)
(?<=\d)(?>\d(?=\d{3})|\G\d|(\d*(?=\d)))(?=\d)

30.不使用括号调用函数

function foo() {
console.log('ok');
}

// 不使用括号(),写出至少三种方式可以调用foo方法并打印 "ok"
解:
//1
foo``;
//2
new foo;
//3
window.valueOf = foo;
+window;

31.匹配aaa,要求aaa前面不能有开括号"(",后面不能有闭括号")",除非在完整的括号中(aaa)

// https://regex101.com/r/vjHUdl/1
匹配aaa,要求aaa前面不能有开括号"(",后面不能有闭括号")"除非在完整的括号中(aaa)
可选要求1:不使用条件分支"|"
可选要求2:不使用lookaround:"(?<=)", "(?<!)", "(?=)", "(?!)"

aaa)
aaa
aaaa
(aaa
(aa)
(aaa)
(aaaa)
(aaaaa)
(aaaaaa)
(aaaaaaa)
(aaaaaaaa)
aaaa)aaa(aaa)aaaa(aaaa)aa(aaa(aaaaa)aaaaaaaaaa
解:
/(\()?a(*SKIP)aa(?(1)\)(*ACCEPT))(\)(*SKIP)(*F))?/gm