Javascript 在Javascript中用大写替换正则表达式捕获组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6142922/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Replace a Regex capture group with uppercase in Javascript
提问by Evan Carroll
I'd like to know how to replace a capture group with its uppercase in JavaScript. Here's a simplified version of what I've tried so far that's not working:
我想知道如何在 JavaScript 中用大写替换捕获组。这是我迄今为止尝试过但不起作用的简化版本:
> a="foobar"
'foobar'
> a.replace( /(f)/, "".toUpperCase() )
'foobar'
> a.replace( /(f)/, String.prototype.toUpperCase.apply("") )
'foobar'
Would you explain what's wrong with this code?
你能解释一下这段代码有什么问题吗?
回答by ChaosPandion
You can pass a function to replace
.
您可以将函数传递给replace
.
var r = a.replace(/(f)/, function(v) { return v.toUpperCase(); });
Explanation
解释
a.replace( /(f)/, "".toUpperCase())
In this example you pass a string to the replace function. Since you are using the special replace syntax ($N grabs the Nth capture)you are simply giving the same value. The toUpperCase
is actually deceiving because you are only making the replace string upper case (Which is somewhat pointless because the $
and one 1
characters have no upper case so the return value will still be "$1"
).
在本例中,您将一个字符串传递给替换函数。由于您使用的是特殊的替换语法($N 获取第 N 个捕获),因此您只需提供相同的值。这toUpperCase
实际上是在欺骗,因为您只是将替换字符串设为大写(这有点毫无意义,因为$
和 一个1
字符没有大写,因此返回值仍然是"$1"
)。
a.replace( /(f)/, String.prototype.toUpperCase.apply(""))
Believe it or not the semantics of this expression are exactly the same.
信不信由你,这个表达式的语义是完全一样的。
回答by Joshua Piccari
I know I'm late to the party but here is a shorter method that is more along the lines of your initial attempts.
我知道我迟到了,但这里有一个更短的方法,更符合你最初的尝试。
a.replace('f', String.call.bind(a.toUpperCase));
So where did you go wrong and what is this new voodoo?
那么你哪里出错了,这个新的伏都教是什么?
Problem 1
问题一
As stated before, you were attempting to pass the results of a called method as the second parameter of String.prototype.replace(), when instead you ought to be passing a reference to a function
如前所述,您试图将被调用方法的结果作为String.prototype.replace()的第二个参数传递,而您应该传递对函数的引用
Solution 1
解决方案1
That's easy enough to solve. Simply removing the parameters and parentheses will give us a reference rather than executing the function.
这很容易解决。简单地删除参数和括号会给我们一个引用而不是执行函数。
a.replace('f', String.prototype.toUpperCase.apply)
Problem 2
问题二
If you attempt to run the code now you will get an error stating that undefined is not a function and therefore cannot be called. This is because String.prototype.toUpperCase.apply is actually a reference to Function.prototype.apply()via JavaScript's prototypical inheritance. So what we are actually doing looks more like this
如果您现在尝试运行代码,您将收到一条错误消息,指出 undefined 不是函数,因此无法调用。这是因为 String.prototype.toUpperCase.apply 实际上是通过 JavaScript 的原型继承对Function.prototype.apply()的引用。所以我们实际上在做的事情看起来更像这样
a.replace('f', Function.prototype.apply)
Which is obviously not what we have intended. How does it know to run Function.prototype.apply()on String.prototype.toUpperCase()?
这显然不是我们的意图。它怎么知道在String.prototype.toUpperCase()上运行Function.prototype.apply ()?
Solution 2
解决方案2
Using Function.prototype.bind()we can create a copy of Function.prototype.call with its context specifically set to String.prototype.toUpperCase. We now have the following
使用Function.prototype.bind()我们可以创建 Function.prototype.call 的副本,并将其上下文专门设置为 String.prototype.toUpperCase。我们现在有以下
a.replace('f', Function.prototype.apply.bind(String.prototype.toUpperCase))
Problem 3
问题三
The last issue is that String.prototype.replace()will pass several arguments to its replacement function. However, Function.prototype.apply()expects the second parameter to be an array but instead gets either a string or number (depending on if you use capture groups or not). This would cause an invalid argument list error.
最后一个问题是String.prototype.replace()将向其替换函数传递几个参数。但是,Function.prototype.apply()期望第二个参数是一个数组,而是获取一个字符串或数字(取决于您是否使用捕获组)。这将导致无效参数列表错误。
Solution 3
解决方案3
Luckily, we can simply substitute in Function.prototype.call()(which accepts any number of arguments, none of which have type restrictions) for Function.prototype.apply(). We have now arrived at working code!
幸运的是,我们可以简单地将Function.prototype.call()(它接受任意数量的参数,没有类型限制)替换为Function.prototype.apply()。我们现在已经到达了工作代码!
a.replace(/f/, Function.prototype.call.bind(String.prototype.toUpperCase))
Shedding bytes!
脱落字节!
Nobody wants to type prototypea bunch of times. Instead we'll leverage the fact that we have objects that reference the same methods via inheritance. The String constructor, being a function, inherits from Function's prototype. This means that we can substitute in String.call for Function.prototype.call(actually we can use Date.call to save even more bytes but that's less semantic).
没有人愿意多次输入原型。相反,我们将利用这样一个事实,即我们拥有通过继承引用相同方法的对象。String 构造函数是一个函数,它继承自 Function 的原型。这意味着我们可以在 String.call 中替换Function.prototype.call(实际上我们可以使用 Date.call 来节省更多字节,但语义更少)。
We can also leverage our variable 'a' since it's prototype includes a reference to String.prototype.toUpperCasewe can swap that out with a.toUpperCase. It is the combination of the 3 solutions above and these byte saving measures that is how we get the code at the top of this post.
我们还可以利用我们的变量“a”,因为它的原型包含对String.prototype.toUpperCase的引用,我们可以将其替换为 a.toUpperCase。正是上述 3 种解决方案和这些字节节省措施的组合,这就是我们获得本文顶部代码的方式。
回答by CallMeLaNN
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/
:
旧帖子,但值得为其他使用更受限制的 RegEx 用例扩展 @ChaosPandion 答案。例如,确保(f)
使用特定格式的或捕获组环绕/z(f)oo/
:
> a="foobazfoobar"
'foobazfoobar'
> a.replace(/z(f)oo/, function(a.replace(/(f)/, x => x.toUpperCase())
,) {return a.replace('f','F')
.replace(, .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.
我只想强调function
使查找特定格式和替换格式中的捕获组的两个参数。
回答by Bernhard Wagner
Why don't we just look up the definition?
我们为什么不查一下定义呢?
If we write:
如果我们写:
function replacer(match, p1, p2, p3, offset, string)
we might as well just say:
我们不妨说:
a.replace(/xxx(yyy)zzz/, (match, p1) => p1.toUpperCase()
Worse, I suspect nobody realises that their examples have been working only because they were capturing the whole regexwith parentheses. If you look at the definition, the first parameter passed to the replacer
function is actually the whole matched patternand not the pattern you captured with parentheses:
更糟糕的是,我怀疑没有人意识到他们的例子之所以有效,只是因为他们用括号捕获了整个正则表达式。如果查看定义,传递给replacer
函数的第一个参数实际上是整个匹配的模式,而不是您用括号捕获的模式:
a.replace(/(f)/,x=>x.toUpperCase())
If you want to use the arrow function notation:
如果要使用箭头函数表示法:
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);
回答by Kamil Kie?czewski
SOLUTION
解决方案
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);
for replace all grup occurrences use /(f)/g
regexp. The problem in your code: String.prototype.toUpperCase.apply("$1")
and "$1".toUpperCase()
gives "$1"
(try in console by yourself) - so it not change anything and in fact you call twice a.replace( /(f)/, "$1")
(which also change nothing).
使用正则/(f)/g
表达式替换所有出现的组。您的代码中的问题:String.prototype.toUpperCase.apply("$1")
并"$1".toUpperCase()
给出"$1"
(自己在控制台中尝试)-因此它不会改变任何内容,实际上您调用了两次a.replace( /(f)/, "$1")
(也不会改变任何内容)。
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);
回答by guest271314
Given a dictionary (object, in this case, a Map
) of property, values, and using .bind()
as described at answers
给定一个Map
包含属性、值和使用的字典(对象,在本例中为 a ),.bind()
如答案中所述
Using a JavaScript plain object and with a function defined to get return matched property value of the object, or original string if no match is found
使用 JavaScript 普通对象并定义一个函数以获取返回对象的匹配属性值,如果未找到匹配,则返回原始字符串