我想知道如何在JavaScript中用大写替换捕获组。这是我迄今为止尝试过的一个简化版本,它不起作用:
> a="foobar"
'foobar'
> a.replace( /(f)/, "$1".toUpperCase() )
'foobar'
> a.replace( /(f)/, String.prototype.toUpperCase.apply("$1") )
'foobar'
你能解释这段代码有什么问题吗?
答案 0 :(得分:136)
您可以将功能传递给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"))
信不信由这个表达式的语义完全相同。
答案 1 :(得分:11)
我知道我迟到了,但这是一个更短的方法,更符合你最初的尝试。
a.replace('f', String.call.bind(a.toUpperCase));
那你哪里出错了,这个新的伏都教是什么?
如前所述,您试图将被调用方法的结果作为String.prototype.replace()的第二个参数传递,而您应该将引用传递给函数
这很容易解决。简单地删除参数和括号将为我们提供参考而不是执行函数。
a.replace('f', String.prototype.toUpperCase.apply)
如果您现在尝试运行代码,则会收到错误消息,指出undefined不是函数,因此无法调用。这是因为String.prototype.toUpperCase.apply实际上是通过JavaScript的原型继承引用Function.prototype.apply()。所以我们实际上看起来更像是这个
a.replace('f', Function.prototype.apply)
这显然不是我们想要的。如何在Function.prototype.apply()上运行String.prototype.toUpperCase()?
使用Function.prototype.bind(),我们可以创建一个Function.prototype.call的副本,其上下文专门设置为String.prototype.toUpperCase。我们现在有以下
a.replace('f', Function.prototype.apply.bind(String.prototype.toUpperCase))
最后一个问题是String.prototype.replace()会将几个参数传递给它的替换函数。但是,Function.prototype.apply()期望第二个参数是一个数组,而是获取字符串或数字(取决于您是否使用捕获组)。这将导致无效的参数列表错误。
幸运的是,我们可以简单地用Function.prototype.call()替换Function.prototype.apply()(它接受任意数量的参数,其中没有一个具有类型限制)。Function.prototype.call。我们现在已经到了工作代码!
a.replace(/f/, Function.prototype.call.bind(String.prototype.toUpperCase))
没有人想要多次输入 prototype 。相反,我们将利用我们拥有通过继承引用相同方法的对象这一事实。作为函数的String构造函数继承自Function的原型。这意味着我们可以在String.call中替换String.prototype.toUpperCase(实际上我们可以使用Date.call来保存更多的字节,但语义更少)。
我们还可以利用我们的变量&#39; a&#39;因为它的原型包含对{{3}}的引用,我们可以用a.toUpperCase交换它。它是上述3种解决方案和这些节省字节的措施的组合,这就是我们如何在这篇文章的顶部获得代码。
答案 2 :(得分:5)
Old post but it worth to extend @ChaosPandion answer for other use cases with more restricted RegEx. E.g. ensure the (f)
or capturing group surround with a specific format /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.
I just want to highlight the two parameters of function
makes finding a specific format and replacing a capturing group within the format possible.
答案 3 :(得分:2)
解决方案
a.replace(/(f)/,x=>x.toUpperCase())
使用/(f)/g
正则表达式替换所有出现的组。您的代码中的问题:String.prototype.toUpperCase.apply("$1")
和"$1".toUpperCase()
给出了"$1"
(您自己在控制台中尝试)-因此它不会改变任何内容,实际上您调用了两次a.replace( /(f)/, "$1")
(什么都不要改变)。
let a= "foobar";
let b= a.replace(/(f)/,x=>x.toUpperCase());
let c= a.replace(/(o)/g,x=>x.toUpperCase());
console.log("/(f)/ ", b);
console.log("/(o)/g", c);
答案 4 :(得分:0)
给出属性,值的字典(在这种情况下为Map
),并按照答案中的描述使用.bind()
const regex = /([A-z0-9]+)/;
const dictionary = new Map([["hello", 123]]);
let str = "hello";
str = str.replace(regex, dictionary.get.bind(dictionary));
console.log(str);
使用JavaScript普通对象并定义一个函数以获取对象的返回匹配属性值,如果找不到匹配项,则返回原始字符串
const regex = /([A-z0-9]+)/;
const dictionary = {
"hello": 123,
[Symbol("dictionary")](prop) {
return this[prop] || prop
}
};
let str = "hello";
str = str.replace(regex, dictionary[Object.getOwnPropertySymbols(dictionary)[0]].bind(dictionary));
console.log(str);
答案 5 :(得分:0)
为什么我们不只是查找the definition?
如果我们写:
a.replace(/(f)/, x => x.toUpperCase())
我们不妨说:
a.replace('f','F')
更糟糕的是,我怀疑没有人意识到他们的例子之所以有用,仅仅是因为他们用括号捕获了整个正则表达式。如果您查看the definition,则传递给replacer
函数的第一个参数实际上是完全匹配的模式,而不是用括号捕获的模式:
function replacer(match, p1, p2, p3, offset, string)
如果要使用箭头功能符号:
a.replace(/xxx(yyy)zzz/, (match, p1) => p1.toUpperCase()