11
2- # 粘性标志 "y",在位置处搜索
2+ # 粘性修饰符 "y",在位置处搜索
33
4- ` pattern:y ` 标志允许在源字符串中的指定位置执行搜索 。
4+ ` pattern:y ` 修饰符让我们能够在源字符串中的指定位置进行搜索 。
55
6- 为了掌握 ` pattern:y ` 标志的用例,看看它有多好,让我们来探讨一个实际的用例 。
6+ 为了掌握 ` pattern:y ` 修饰符的使用方式,让我们来看一个实际的例子 。
77
8- regexps 的常见任务之一是" 词法分析":比如我们在程序设计语言中得到一个文本,然后分析它的结构元素 。
8+ 正则表达式的常见任务之一就是“ 词法分析”:例如我们得到了一个代码文本,我们需要找到它的结构元素。例如,HTML 有标签和特性(attribute),JavaScript 代码有函数、变量等 。
99
10- 例如,HTML 有标签和属性,JavaScript 代码有函数、变量等 。
10+ 编写词法分析器是一个特殊的领域,有自己的工具和算法,所以我们不做过多的深入,但有一个共同的任务:在给定的位置读取一些内容 。
1111
12- 编写词法分析器是一个特殊的领域,有自己的工具和算法,所以我们就不深究了,但有一个共同的任务:在给定的位置读出一些东西 。
12+ 例如,我们有一个代码字符串 ` subject:let varName = "value" ` ,我们需要从中读取变量名,这个变量名从位置 ` 4 ` 开始 。
1313
14- 例如,我们有一个代码字符串 ` subject:let varName = "value" ` ,我们需要从其中读取变量名,这个变量名从位置 ` 4 ` 开始 。
14+ 我们将使用正则表达式 ` pattern:\w+ ` 来查找变量名。实际上,JavaScript 的变量名需要更复杂的正则表达式才能准确匹配,但在这里并不重要 。
1515
16- 我们用 regexp ` pattern:\w+ ` 来查找变量名。实际上,JavaScript 的变量名需要更复杂的 regexp 来进行准确的匹配,但在这里并不重要。
16+ - 调用 ` str.match(/\w+/) ` 将只会找到该行中的第一个单词 (` let ` )。不是这个。
17+ - 我们可以添加修饰符 ` pattern:g ` 。但是调用 ` str.match(/\w+/g) ` 会查找文本中的所有单词,而我们需要位置 ` 4 ` 的一个单词。同样,不是我们需要的。
1718
18- 调用 ` str.match(/\w+/) ` 将只找到该行中的第一个单词。或者是所有带标记 ` pattern:g ` 的单词。但我们只需要在位置 ` 4 ` 的一个词 。
19+ ** 那么,如何在给定位置准确搜索正则表达式? ** 。
1920
20- 要从给定位置搜索,我们可以使用方法 ` regexp.exec(str) ` 。
21+ 让我们尝试使用方法 ` regexp.exec(str) ` 。
2122
22- 如果 ` regexp ` 没有标志 ` pattern:g ` 或 ` pattern:y ` ,那么这个方法就可以寻找字符串 ` str ` 中的第一个匹配, 就像 ` str.match(regexp) ` 一样。这种简单的无标志的情况我们在这里并不感兴趣 。
23+ 对于没有修饰符 ` pattern:g ` 和 ` pattern:y ` 的 ` regexp ` ,此方法仅查找第一个匹配项, 就像 ` str.match(regexp) ` 一样。
2324
24- 如果有标志 ` pattern:g ` ,那么它就会在字符串 ` str ` 中执行搜索,从存储在 ` regexp.lastIndex ` 属性中的位置开始。如果发现匹配,则将 ` regexp.lastIndex ` 设置为匹配后的索引 。
25+ ……但是如果有修饰符 ` pattern:g ` ,那么它就会从存储在 ` regexp.lastIndex ` 属性中的位置开始在字符串 ` str ` 中进行搜索。如果找到匹配项,则将在匹配后立即将 ` regexp.lastIndex ` 设置为索引 。
2526
26- 当一个 regexp 被创建时,它的 ` lastIndex ` 是 ` 0 ` 。
27+ 换句话说, ` regexp.lastIndex ` 作为搜索的起点,每个 ` regexp.exec(str) ` 调用都会将其重置为新值(“在最后一次匹配后”)。当然,这只是在有 ` pattern:g ` 修饰符的情况下才会这样 。
2728
2829因此,连续调用 ` regexp.exec(str) ` 会一个接一个地返回匹配。
2930
30- 一个例子(用标志 ` pattern:g ` ) :
31+ 以下是此类调用的示例 :
3132
3233``` js run
33- let str = ' let varName' ;
34-
34+ let str = ' let varName' ; // 让我们找出字符串中的所有单词
3535let regexp = / \w + / g ;
36- alert (regexp .lastIndex ); // 0(最初 lastIndex=0)
36+
37+ alert (regexp .lastIndex ); // 0 (初始值 lastIndex=0)
3738
3839let word1 = regexp .exec (str);
39- alert (word1[0 ]); // let( 第一个单词)
40- alert (regexp .lastIndex ); // 3( 匹配后的位置)
40+ alert (word1[0 ]); // let ( 第一个单词)
41+ alert (regexp .lastIndex ); // 3 ( 匹配后的位置)
4142
4243let word2 = regexp .exec (str);
4344alert (word2[0 ]); // varName (第二个单词)
44- alert (regexp .lastIndex ); // 11( 匹配后的位置)
45+ alert (regexp .lastIndex ); // 11 ( 匹配后的位置)
4546
4647let word3 = regexp .exec (str);
47- alert (word3); // null(没有更多的匹配)
48- alert (regexp .lastIndex ); // 0(搜索结束时重置)
48+ alert (word3); // null (没有更多匹配项)
49+ alert (regexp .lastIndex ); // 0 (搜索结束后重置索引)
4950```
5051
51- 每个匹配都会以数组形式返回,包含分组和附加属性。
52-
53- 我们可以在循环中得到所有的匹配。
52+ 我们可以通过循环获取所有匹配。
5453
5554``` js run
5655let str = ' let varName' ;
@@ -60,21 +59,23 @@ let result;
6059
6160while (result = regexp .exec (str)) {
6261 alert ( ` Found ${ result[0 ]} at position ${ result .index } ` );
63- // 在位置 0 发现 let, 然后
62+ // 在位置 0 发现了 let, 然后
6463 // 在位置 4 发现 varName
6564}
6665```
6766
68- ` regexp.exec ` 是 ` str.matchAll ` 方法的替代方法。
67+ ` regexp.exec ` 的这种使用方式可以作为 ` str.matchAll ` 方法的替代,可以对匹配过程进行更多控制。
68+
69+ 让我们回到我们的任务。
6970
70- 与其他方法不同,我们可以设置自己的 ` lastIndex ` ,从给定位置开始搜索。
71+ 我们可以手动将 ` lastIndex ` 设置为 ` 4 ` ,从给定的位置开始搜索!
7172
72- 例如,让我们从位置 ` 4 ` 开始寻找一个单词。
73+ 像这样:
7374
7475``` js run
7576let str = ' let varName = "value"' ;
7677
77- let regexp = / \w + / g ; // 如果没有标志 "g",属性 lastIndex 会被忽略
78+ let regexp = / \w + / g ; // 没有修饰符 "g",lastIndex 属性会被忽略
7879
7980* ! *
8081regexp .lastIndex = 4 ;
@@ -84,29 +85,37 @@ let word = regexp.exec(str);
8485alert (word); // varName
8586```
8687
87- 我们从位置 ` regexp.lastIndex = 4 ` 开始搜索 ` pattern:w+ ` 。
88+ 哇塞!问题解决了!
8889
89- 请注意:搜索从位置 ` lastIndex ` 开始,然后再往前走。如果在 ` lastIndex ` 位置上没有词,但它在后面的某个地方,那么它就会被找到:
90+ 我们从位置 ` regexp.lastIndex = 4 ` 开始搜索 ` pattern:\w+ ` 。
91+
92+ 结果是正确的。
93+
94+ ……但是等等,没那么快。
95+
96+ 请注意:` regexp.exec ` 调用从位置 ` lastIndex ` 开始搜索,然后继续搜索。如果 ` lastIndex ` 位置没有单词,但单词在这之后的某个位置,那么单词也会被找到:
9097
9198``` js run
9299let str = ' let varName = "value"' ;
93100
94101let regexp = / \w + / g ;
95102
96103* ! *
104+ // 从位置 3 开始搜索
97105regexp .lastIndex = 3 ;
98106*/ ! *
99107
100- let word = regexp .exec (str);
108+ let word = regexp .exec (str);
109+ // 在位置 4 找到匹配项
101110alert (word[0 ]); // varName
102111alert (word .index ); // 4
103112```
104113
105- ……所以,用标志 ` pattern:g ` 属性 ` lastIndex ` 设置搜索的起始位置 。
114+ 对于某些任务,包括词法分析,这是错误的。我们需要在文本的给定位置准确地找到匹配,而不是在它之后的某个位置。这就是修饰符 "y" 的用途 。
106115
107- ** 标记 ` pattern:y ` 使 ` regexp.exec ` 正好在 ` lastIndex ` 位置,而不是在它之前,也不是在它之后 。**
116+ ** 修饰符 ` pattern:y ` 使 ` regexp.exec ` 精确搜索位置 ` lastIndex ` ,而不是“从”它开始 。**
108117
109- 下面是使用标志 ` pattern:y ` 进行同样的搜索。
118+ 下面是带有修饰符 ` pattern:y ` 的相同搜索:
110119
111120``` js run
112121let str = ' let varName = "value"' ;
@@ -120,8 +129,10 @@ regexp.lastIndex = 4;
120129alert ( regexp .exec (str) ); // varName(在位置 4 的单词)
121130```
122131
123- 我们可以看到,regexp ` pattern:/\w+/y ` 在位置 ` 3 ` 处不匹配(不同于标志 ` pattern:g ` ),而是在位置 ` 4 ` 处匹配。
132+ 正如我们所看到的,正则表达式 ` pattern:/\w+/y ` 在位置 ` 3 ` 处不匹配(不同于修饰符 ` pattern:g ` ),但在位置 ` 4 ` 处匹配。
133+
134+ 这不仅是我们所需要的,当使用修饰符 ` pattern:y ` 时,还有一个重要的性能提升。
124135
125- 想象一下,我们有一个长的文本,而里面根本没有匹配。那么用标志 ` pattern:g ` 搜索将一直到文本的最后,这将比用标志 ` pattern:y ` 搜索要花费更多的时间 。
136+ 想象一下,我们有一个很长的文本,其中根本没有匹配项。然后使用修饰符 ` pattern:g ` 进行搜索,会一直搜索到文本的末尾,并且什么也找不到,这将比使用修饰符 ` pattern:y ` 的搜索花费更多的时间,后者只检查确切的位置 。
126137
127- 在像词法分析这样的任务中,通常在一个确切的位置会有很多搜索。使用标志 ` pattern:y ` 是获得良好性能的关键 。
138+ 在像词法分析这样的任务中,通常会在一个确切的位置进行多次搜索,以检查我们在那里有什么。使用修饰符 ` pattern:y ` 是正确实现和良好性能的关键 。
0 commit comments