# 几个基础概念

## 部分正则规则

### 常用符号

\ 转义字符。匹配数据不想被正则规则解析
^ 匹配输入的开始。注意，和在 [] 中定义的不同
\$ 匹配输入的结束
? 0 or 1 次，等价 {0,1}
. 换行 \n 之外的单个字符
x | y ‘x’或者‘y’

### 多次匹配

* 0 or 多次 等价 {0,}
+ 1 or 多次，至少出现一次。等价 {1,}
{n} 匹配重复出现 n 次
{n,m} n<= 匹配出现次数 <=m

### 任意字符

[xyz] 匹配方括号中的任意字符
[^xyz] 匹配任何没有包含在方括号中的字符（反向字符集）

### 特殊字符

\b 匹配一个词的边界（前后没有其他字符）
\s 匹配任何空白字符（空格、制表符、换页符等），等价 [ \f\n\r\t\v]。
\S 匹配任何非空白字符。等价 [^ \f\n\r\t\v]。
\w 匹配包括下划线的任何单词字符。等价 “[A-Za-z0-9_]”。
\W 匹配任何非单词字符。等价 “[^a-za-z0-9_]”。

### 特殊规则

(x) 捕获括号（匹配 'x' 并且记住匹配项
(?:x) 非捕获括号（匹配 'x' 但是不记住匹配项
x(?=y) 正向肯定查找
x(?!y) 正向否定查找

## test exec match 区别

• test 不需要知道匹配内容，只需判断正则是否命中的场景
• exec 进行搜索匹配，返回匹配结果
• match 是 String 对象方法，和 exec 类似

``````// 基本使用
let numRE = /[0-9]+/;
let data2 = "abc123efg456";

console.log(numRE.test(data2)); // true
console.log(numRE.exec(data2)); // [ '123', index: 3, input: 'abc123efg456' ]
console.log(data2.match(numRE)); // [ '123', index: 3, input: 'abc123efg456' ]

// 对比 exec ， match
let numGobalRE = /[0-9]+/g;

console.log(numGobalRE.test(data2)); // true
console.log(numGobalRE.exec(data2)); // [ '456', index: 9, input: 'abc123efg456' ]
console.log(data2.match(numGobalRE)); // [ '123', '456' ]``````

## 非括号捕获

``````/**
* 非括号捕获
*/
const nonCapturingRE = /(?:abc){1}/;
// [ 'abc', index: 0, input: 'abc' ]
console.log("abcefg".match(nonCapturingRE));

/**
* 括号捕获
*/
const capturingRE = /(abc){1}/;
// [ 'abc', 'abc', index: 0, input: 'abcefg' ]
console.log("abcefg".match(capturingRE));``````

``````let result1 = "abcefg".replace(nonCapturingRE, "hello \$1 "); // hello \$1 efg
let result2 = "abcefg".replace(capturingRE, "hello \$1 "); // hello abc efg``````

## replace

replace 作为 String 对象中的方法，相比都经常使用。

``string.replace(Regexp, Function);``

Function 的参数说明：

• match 匹配内容
• \$1,\$2 ... 括号捕获内容
• offset 匹配开始位置
• string 源字符串

``````var re = /(\w+)\s(\w+)/;
var str = "John Smith";
var newstr = str.replace(re, function(...args) {
console.log(args); // ["John Smith", "John", "Smith", 0, "John Smith"]
});``````
``````var re = /(?:\w+)\s(\w+)/; // 将其中一个调整为 非括号捕获
console.log(args); // ["John Smith", "Smith", 0, "John Smith"]``````

# html 注释判断

vue 会解析我们 html 模板，html 中的注释肯定没有任何意义，所以有必要将它过滤掉。

``````<!-- 我是个注释 -->
<div>hello</div>

<!--[if !IE]>-->
<div>我是个低端浏览器</div>``````

``````const comment = /^<!\--/;
const conditionalComment = /^<!\[/;

// 匹配注释
if (comment.test(html)) {
const commentEnd = html.indexOf("-->"); // 记录注释右关闭起始位置

if (commentEnd >= 0) {
continue;
}
}

// 匹配浏览器注释
if (conditionalComment.test(html)) {
const conditionalEnd = html.indexOf("]>"); // 记录注释右关闭起始位置

if (conditionalEnd >= 0) {
continue;
}
}``````

# 驼峰表达式转换

``````const camelizeRE = /-(\w)/g;
const camelize = str => {
return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ""));
};``````

# 解析 html 属性 KV

``const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/;``

``````'id="app" class="foo">hello</div>'.match(attribute);
// ["id="app"", "id", "=", "app", undefined, undefined, index: 0, input: "id="app" class="red" disabled></div>", groups: undefined]

"id='app' class='foo'>hello</div>".match(attribute);
// ["id='app'", "id", "=", undefined, "app", undefined, index: 0, input: "id='app' class='red' disabled></div>", groups: undefined]

"  disabled>hello</div>".match(attribute);
// ["  disabled", "disabled", undefined, undefined, undefined, undefined, index: 0, input: "disabled>hello</div>", groups: undefined]``````

``/A(B)(?:C(?(?(D)|(E)|(F))))/``

``^\s*``

``([^\s"'<>\/=]+)``

[] 中括号包裹，并且里面匹配的内容至少要出现一次。

``(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?``

``"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)``

F 和之前的 B 类似，唯独去除了斜杠限制。

``(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+))``

``(?:\s*(=)\s*(?(D)|(E)|(F)))``

# 正则的封装

``/^<((?:[a-zA-Z_][\-\.0-9_a-zA-Za-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]*\:)?[a-zA-Z_][\-\.0-9_a-zA-Za-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]*)/``

``````const unicodeRegExp = /a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD/;

const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z\${unicodeRegExp.source}]*`;
const qnameCapture = `((?:\${ncname}\\:)?\${ncname})`;
const startTagOpen = new RegExp(`^<\${qnameCapture}`);``````
{"ft_lang_label":"__label__zh","ft_lang_prob":0.64259315,"math_prob":0.9789547,"size":5775,"snap":"2020-45-2020-50","text_gpt3_token_len":3378,"char_repetition_ratio":0.094957545,"word_repetition_ratio":0.019933555,"special_character_ratio":0.3939394,"punctuation_ratio":0.19901478,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.96402603,"pos_list":[0],"im_url_duplicate_count":[null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2020-11-27T17:35:20Z\",\"WARC-Record-ID\":\"<urn:uuid:cda4f24e-440a-4a50-8390-20983034e077>\",\"Content-Length\":\"669282\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:623d1375-3341-45a4-8f56-b23332ff98f8>\",\"WARC-Concurrent-To\":\"<urn:uuid:9ceb0e85-ce77-42e6-965f-9edf61a57725>\",\"WARC-IP-Address\":\"47.103.139.109\",\"WARC-Target-URI\":\"http://eminoda.com/post/5f42a053aa2a691bfcb1af04\",\"WARC-Payload-Digest\":\"sha1:FELCBGNGJVZQXFMS5PQIKRQUFF7C7F4Q\",\"WARC-Block-Digest\":\"sha1:XIP6SMVFB7JDXK3OLFZTUXWO775KZVYY\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2020/CC-MAIN-2020-50/CC-MAIN-2020-50_segments_1606141193856.40_warc_CC-MAIN-20201127161801-20201127191801-00085.warc.gz\"}"}