用Javascript中的大写替换正则表达式捕获组

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (84)

我想知道如何用JavaScript中的大写替换捕获组。以下是迄今为止我尝试过的一个简化版本,它不起作用:

> a="foobar"
'foobar'
> a.replace( /(f)/, "$1".toUpperCase() )
'foobar'
> a.replace( /(f)/, String.prototype.toUpperCase.apply("$1") )
'foobar'

你能解释这段代码有什么问题吗?

提问于
用户回答回答于

你可以传递一个函数给replace

var r = a.replace(/(f)/, function(v) { return v.toUpperCase(); });

说明

a.replace( /(f)/, "$1".toUpperCase())

在这个例子中,你将一个字符串传递给replace函数。由于您使用的是特殊替换语法($ N抓取第N次抓取),因此您只需提供相同的值。这toUpperCase实际上是在欺骗,因为你只是在替换字符串大写(这有点毫无意义,因为$和一个1字符没有大写,所以返回值仍然是"$1"

a.replace( /(f)/, String.prototype.toUpperCase.apply("$1"))

相信这个表达的语义是否完全一样。

用户回答回答于

我知道我迟到了,但这是一个更短的方法,更符合你最初的尝试。

a.replace('f', String.call.bind(a.toUpperCase));

那么你哪里出了问题,这个新的巫术是什么?

问题1

如前所述,您试图将被调用方法的结果作为String.prototype.replace()的第二个参数传递,而您应该将引用传递给函数

解决方案1

这很容易解决。简单地删除参数和括号会给我们一个参考而不是执行这个函数。

a.replace('f', String.prototype.toUpperCase.apply)

问题2

如果你现在试图运行代码,你会得到一个错误,说明undefined不是一个函数,因此不能被调用。这是因为String.prototype.toUpperCase.apply实际上是通过JavaScript的原型继承对Function.prototype.apply()的引用。所以我们实际上做的更像这样

a.replace('f', Function.prototype.apply)

这显然不是我们的意图。它如何知道在String.prototype.toUpperCase()上运行Function.prototype.apply ()

解决方案2

使用Function.prototype.bind(),我们可以创建一个Function.prototype.call的副本,并将其上下文专门设置为String.prototype.toUpperCase。我们现在有以下几点

a.replace('f', Function.prototype.apply.bind(String.prototype.toUpperCase))

问题3

最后一个问题是String.prototype.replace()会将几个参数传递给它的替换函数。然而,Function.prototype.apply()期望第二个参数是一个数组,但取而代之的是一个字符串或数字(取决于是否使用捕获组)。这会导致无效的参数列表错误。

解决方案3

幸运的是,对于Function.prototype.apply(),我们可以简单地在Function.prototype.call()中进行替换(它接受任意数量的参数,其中没有类型限制。我们现在已经到达工作代码!

a.replace(/f/, Function.prototype.call.bind(String.prototype.toUpperCase))

没有人想要多次打印原型。相反,我们将利用事实,即我们有通过继承引用相同方法的对象。作为函数的String构造函数继承自Function的原型。这意味着我们可以在String.call中替换Function.prototype.call(实际上我们可以使用Date.call来保存更多的字节,但这种语义更少)。

我们还可以利用变量'a',因为原型包含对String.prototype.toUpperCase的引用,我们可以用a.toUpperCase替换它。这是上述3个解决方案的组合,以及这些字节保存措施,这就是我们如何获得这篇文章顶部的代码。

扫码关注云+社区