Eva*_*oll 67 javascript regex replace uppercase
我想知道如何用JavaScript中的大写替换捕获组.这是我迄今为止尝试过的一个简化版本,它不起作用:
> a="foobar"
'foobar'
> a.replace( /(f)/, "$1".toUpperCase() )
'foobar'
> a.replace( /(f)/, String.prototype.toUpperCase.apply("$1") )
'foobar'
Run Code Online (Sandbox Code Playgroud)
你能解释一下这段代码有什么问题吗?
Cha*_*ion 141
你可以传递一个函数replace
.
var r = a.replace(/(f)/, function(v) { return v.toUpperCase(); });
Run Code Online (Sandbox Code Playgroud)
说明
a.replace( /(f)/, "$1".toUpperCase())
Run Code Online (Sandbox Code Playgroud)
在此示例中,您将字符串传递给replace函数.由于您使用的是特殊替换语法($ N抓取第N次捕获),因此您只需提供相同的值.这toUpperCase
实际上是欺骗,因为你只是使替换字符串大写(这有点无意义,因为$
和一个1
字符没有大写,所以返回值仍然是"$1"
).
a.replace( /(f)/, String.prototype.toUpperCase.apply("$1"))
Run Code Online (Sandbox Code Playgroud)
信不信由你,这个表达的语义是完全一样的.
Jos*_*ari 11
我知道我迟到了,但这是一个更短的方法,更符合你最初的尝试.
a.replace('f', String.call.bind(a.toUpperCase));
Run Code Online (Sandbox Code Playgroud)
所以你哪里出错了,这个新的伏都教是什么?
如前所述,您试图将被调用方法的结果作为String.prototype.replace()的第二个参数传递,而您应该将引用传递给函数
这很容易解决.简单地删除参数和括号将为我们提供参考,而不是执行该功能.
a.replace('f', String.prototype.toUpperCase.apply)
Run Code Online (Sandbox Code Playgroud)
如果您现在尝试运行代码,则会收到错误消息,指出undefined不是函数,因此无法调用.这是因为String.prototype.toUpperCase.apply实际上是通过JavaScript的原型继承对Function.prototype.apply()的引用.所以我们实际上看起来更像是这样
a.replace('f', Function.prototype.apply)
Run Code Online (Sandbox Code Playgroud)
这显然不是我们想要的.如何知道在String.prototype.toUpperCase()上运行Function.prototype.apply ()?
使用Function.prototype.bind(),我们可以创建一个Function.prototype.call的副本,其上下文专门设置为String.prototype.toUpperCase.我们现在有以下内容
a.replace('f', Function.prototype.apply.bind(String.prototype.toUpperCase))
Run Code Online (Sandbox Code Playgroud)
最后一个问题是String.prototype.replace()会将几个参数传递给它的替换函数.但是,Function.prototype.apply()期望第二个参数是一个数组,而是获取一个字符串或数字(取决于您是否使用捕获组).这将导致无效的参数列表错误.
幸运的是,我们可以简单地在Function.prototype.apply()中替换Function.prototype.call()(它接受任意数量的参数,其中没有一个具有类型限制).我们现在已经到了工作代码!
a.replace(/f/, Function.prototype.call.bind(String.prototype.toUpperCase))
Run Code Online (Sandbox Code Playgroud)
没有人想要打造原型很多次.相反,我们将利用我们拥有通过继承引用相同方法的对象这一事实.作为函数的String构造函数继承自Function的原型.这意味着我们可以在String.call中替换Function.prototype.call(实际上我们可以使用Date.call来保存更多的字节但是语义更少).
我们也可以利用变量'a',因为它的原型包含对String.prototype.toUpperCase的引用,我们可以用a.toUpperCase交换它.它是上述3种解决方案和这些字节保存措施的组合,这就是我们如何获得此帖子顶部的代码.
Ber*_*ner 10
我们为什么不查一下定义呢?
如果我们写:
a.replace(/(f)/, x => x.toUpperCase())
Run Code Online (Sandbox Code Playgroud)
我们不妨说:
a.replace('f','F')
Run Code Online (Sandbox Code Playgroud)
更糟糕的是,我怀疑没有人意识到他们的例子之所以有效,只是因为他们用括号捕获了整个正则表达式。如果查看定义,传递给replacer
函数的第一个参数实际上是整个匹配的模式,而不是您用括号捕获的模式:
function replacer(match, p1, p2, p3, offset, string)
Run Code Online (Sandbox Code Playgroud)
如果要使用箭头函数表示法:
a.replace(/xxx(yyy)zzz/, (match, p1) => p1.toUpperCase()
Run Code Online (Sandbox Code Playgroud)
旧的帖子,但值得扩展@ChaosPandion答案的其他用例与更受限制的RegEx.例如(f)
,使用特定格式确保或捕获组环绕/z(f)oo/
:
> a="foobazfoobar"
'foobazfoobar'
> a.replace(/z(f)oo/, function($0,$1) {return $0.replace($1, $1.toUpperCase());})
'foobazFoobar'
// Improve the RegEx so `(f)` will only get replaced when it begins with a dot or new line, etc.
Run Code Online (Sandbox Code Playgroud)
我只想强调function
查找特定格式并在格式内替换捕获组的两个参数.