RegExp 的 exec() 函数和 String 的 match() 函数有什么区别?

IT技术 javascript regex
2021-01-23 08:22:10

如果我运行这个:

/([^\/]+)+/g.exec('/a/b/c/d');

我明白了:

["a", "a"]

但是如果我运行这个:

'/a/b/c/d'.match(/([^\/]+)+/g);

然后我得到了预期的结果:

["a", "b", "c", "d"]

有什么不同?

6个回答

exec使用全局正则表达式意味着在循环中使用,因为它仍然会检索所有匹配的子表达式。所以:

var re = /[^\/]+/g;
var match;

while (match = re.exec('/a/b/c/d')) {
    // match is now the next match, in array form.
}

// No more matches.

String.match 为您执行此操作并丢弃捕获的组。

@Ry- 我认为应该注意这种行为是在 ES5 中引入的。在 ES5 之前new RegExp("pattern")/pattern/意味着不同的东西。
2021-03-15 08:22:10
@yeyo:更具体地说,它必须是相同的正则表达式对象。文字不能做到这一点。
2021-03-20 08:22:10
我有一些东西要添加到这个答案中,不应将正则表达式文字放在 while 条件中,像这样while(match = /[^\/]+/g.exec('/a/b/c/d'),否则会创建无限循环!。正如 MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
2021-03-30 08:22:10

一张图更好,你知道...

re_once = /([a-z])([A-Z])/
re_glob = /([a-z])([A-Z])/g

st = "aAbBcC"

console.log("match once="+ st.match(re_once)+ "  match glob="+ st.match(re_glob))
console.log("exec once="+ re_once.exec(st) + "   exec glob="+ re_glob.exec(st))
console.log("exec once="+ re_once.exec(st) + "   exec glob="+ re_glob.exec(st))
console.log("exec once="+ re_once.exec(st) + "   exec glob="+ re_glob.exec(st))

看到不同?

注意:要突出显示,请注意捕获的组(例如:a,A)在匹配的模式(例如:aA)之后返回,它不仅仅是匹配的模式。

/regex/.exec()仅返回找到的第一个匹配项,"string".match()如果您g在正则表达式中使用该标志,则返回所有匹配项

在这里看到:execmatch

如果您的正则表达式是全局的,并且您正在捕获,那么您必须使用 exec。匹配不会返回您所有的捕获。

Match 适用于仅匹配(不捕获)的情况。你运行一次,它会给出所有匹配的数组。(虽然如果正则表达式不是全局的,那么匹配将显示匹配后跟捕获)

Exec 是你在捕获时使用的,每次执行它都会给出匹配,然后是捕获。(仅当正则表达式不是全局的时,匹配才会以给出完整匹配后跟捕获的方式运行)。

Exec 的另一个用途是获取匹配项的索引或位置。当您的正则表达式有一个变量时,您可以使用.lastIndex并获取匹配的位置。正则表达式对象具有.lastIndex,而正则表达式对象就是您所做.exec的。点匹配是在字符串上完成的,然后您将无法执行 regex object dot lastIndex

一个字符串,具有匹配函数,它被传递一个正则表达式。和一个正则表达式,具有 exec 函数,并传递一个字符串

exec 你运行多次。匹配你跑一次

不捕获时使用 match 很好,捕获时可以使用更强大的 exec,因为它有利于捕获捕获,但是如果您在捕获时确实使用 match,请注意它在正则表达式不是全局时显示捕获,但不'当正则表达式是全局的时不显示捕获。

> "azb".match(/a(z)b/);
[ "azb", "z" ]

> "azb".match(/a(z)b/g);
[ "azb" ]
>

另一件事是,如果您使用 exec,请注意它是在正则表达式上调用的,那么如果您为正则表达式使用了一个变量,那么您将拥有更多的权力

当您不将变量用于正则表达式时,您不会获得匹配项,因此在使用 exec 时将变量用于正则表达式

> /./g.exec("abc")
[ "a" ]
> /./g.exec("abc")
[ "a" ]
> /./g.exec("abc")
[ "a" ]
>
> /[a-c]/g.exec("abc")
[ "a" ]
> /[a-c]/g.exec("abc")
[ "a" ]
>

> var r=/[a-c]/g
> r.exec("abc")
[ "a" ]
> r.exec("abc")
[ "b" ]
> r.exec("abc")
[ "c" ]
> r.exec("abc")
null
>

使用exec,您可以获得匹配的“索引”

> var r=/T/g
> r.exec("qTqqqTqqTq");
[ "T" ]
> r.lastIndex
2
> r.exec("qTqqqTqqTq");
[ "T" ]
> r.lastIndex
6
> r.exec("qTqqqTqqTq");
[ "T" ]
> r.lastIndex
9
> r.exec("qTqqqTqqTq");
null
> r.lastIndex
0
>

因此,如果您想要索引或捕获,请使用 exec(请记住,对于“索引”,它给出的“索引”实际上是第 n 次出现,它从 1 开始计数。因此您可以推导出正确的通过减去 1 来索引。正如你所看到的,它给出了 0 - lastIndex 为 0 - 表示未找到)。

如果你想拉伸匹配,你可以在捕获时使用它,但当正则表达式是全局的时不能使用它,当你这样做时,数组的内容不是所有的匹配,而是完整的匹配,然后是捕获。

@MrHIDEn 我不会使用你在错误引用中所做的语言。重要的是显示的内容以及我们能够看到的内容......幕后是否有任何缓存也无关紧要。我已经有一段时间没有研究这个了,但它没有显示所有捕获..即使你做你的例子"a,b,c,aa,bb,cc".match(/(\w+)/g) 发生的事情它显示了所有匹配,碰巧你捕获了每一个匹配,所以如果要显示所有捕获,它将看起来完全相同(cntd)
2021-03-15 08:22:10
@barlop“匹配不会匹配所有捕获”,是认真的吗?"a,b,c,aa,bb,cc".match(/(\w+)/g) => ["a", "b", "c", "aa", "bb", "cc" ]。如何解释它缓存了所有这些?
2021-03-29 08:22:10
是的,理解的工作r.lastIndex是理解的区别的关键因素execmatch
2021-04-04 08:22:10
@barlopIf your regex is global, and you are capturing, then you must use exec. Match won't return all your captures.我在控制台上得到了它。只需复制/粘贴"a,b,c,aa,bb,cc".match(/(\w+)/g);Opera、Firefox。
2021-04-08 08:22:10
(cntd) 所以也许你认为它正在显示捕获,但事实并非如此,它正在显示匹配
2021-04-11 08:22:10

.match()函数str.match(regexp)将执行以下操作:

  • 如果匹配的,则回复:
    • 如果在则表达式中使用g标志:它将返回所有子字符串(忽略捕获组)
    • 如果该g标志在正则表达式中使用:它将返回与regexp.exec(str)
  • 如果没有匹配项,它将返回:
    • null

.match()使用g标志的例子

var str = "qqqABApppabacccaba";
var e1, e2, e3, e4, e5;
e1 = str.match(/nop/g); //null
e2 = str.match(/no(p)/g); //null
e3 = str.match(/aba/g); //["aba", "aba"]
e4 = str.match(/aba/gi); //["ABA", "aba", "aba"]
e5 = str.match(/(ab)a/g); //["aba", "aba"] ignoring capture groups as it is using the g flag

.match()g标识等同于.exec()

e1=JSON.stringify(str.match(/nop/))===JSON.stringify(/nop/.exec(str)); //true
//e2 ... e4 //true
e5=JSON.stringify(str.match(/(ab)a/))===JSON.stringify(/(ab)a/.exec(str)); //true

.exec()函数regexp.exec(str)将执行以下操作:

  • 如果匹配的,则回复:
    • 如果在则表达式中使用g标志:它将返回(每次调用时)一场比赛的。重要提示:如果正则表达式对象未存储在变量中(它需要是同一个对象),则不会进入下一个匹配项[N_MatchedStr, N_Captured1, N_Captured2, ...]N
    • 如果该g标志在正则表达式中使用:它将返回与具有g标志并且第一次且仅被调用一次的相同。
  • 如果没有匹配项,它将返回:
    • null

.exec()示例(存储的正则表达式 + 使用g标志 = 每次调用都会改变):

var str = "qqqABApppabacccaba";
var myexec, rgxp = /(ab)a/gi;

myexec = rgxp.exec(str);
console.log(myexec); //["ABA", "AB"]
myexec = rgxp.exec(str);
console.log(myexec); //["aba", "ab"]
myexec = rgxp.exec(str);
console.log(myexec); //["aba", "ab"]
myexec = rgxp.exec(str);
console.log(myexec); //null

//But in this case you should use a loop:
var mtch, myRe = /(ab)a/gi;
while(mtch = myRe.exec(str)){ //infinite looping with direct regexps: /(ab)a/gi.exec()
    console.log("elm: "+mtch[0]+" all: "+mtch+" indx: "+myRe.lastIndex);
    //1st iteration = elm: "ABA" all: ["ABA", "AB"] indx: 6
    //2nd iteration = elm: "aba" all: ["aba", "ab"] indx: 12
    //3rd iteration = elm: "aba" all: ["aba", "ab"] indx: 18
}

.exec()随每次调用改变时的示例

var str = "qqqABApppabacccaba", myexec, myexec2;

//doesn't go into the next one because no g flag
var rgxp = /(a)(ba)/;
myexec = rgxp.exec(str);
console.log(myexec); //["aba", "a", "ba"]
myexec = rgxp.exec(str);
console.log(myexec); //["aba", "a", "ba"]
//... ["aba", "a", "ba"]

//doesn't go into the next one because direct regexp
myexec2 = /(ab)a/gi.exec(str);
console.log(myexec2); //["ABA", "AB"]
myexec2 = /(ab)a/gi.exec(str);
console.log(myexec2); //["ABA", "AB"]
//... ["ABA", "AB"]