[英]Replace a Regex capture group with uppercase in Javascript
我想知道如何在 JavaScript 中用大写字母替换捕获组。 这是迄今为止我尝试过的但不起作用的简化版本:
> a="foobar"
'foobar'
> a.replace( /(f)/, "$1".toUpperCase() )
'foobar'
> a.replace( /(f)/, String.prototype.toUpperCase.apply("$1") )
'foobar'
你能解释一下这段代码有什么问题吗?
您可以通过 function 来replace
.
var r = a.replace(/(f)/, function(v) { return v.toUpperCase(); });
解释
a.replace( /(f)/, "$1".toUpperCase())
在此示例中,您将字符串传递给替换 function。 由于您使用的是特殊的替换语法($N 获取第 N 次捕获) ,因此您只是给出了相同的值。 toUpperCase
实际上具有欺骗性,因为您只是将替换字符串设为大写(这有点毫无意义,因为$
和一个1
字符没有大写,因此返回值仍然是"$1"
) 。
a.replace( /(f)/, String.prototype.toUpperCase.apply("$1"))
信不信由你,这个表达式的语义是完全一样的。
我知道我迟到了,但这里有一个更短的方法,更符合你最初的尝试。
a.replace('f', String.call.bind(a.toUpperCase));
那么你在哪里 go 错了,这个新的巫毒是什么?
如前所述,您试图将调用方法的结果作为String.prototype.replace()的第二个参数传递,而您应该传递对 function 的引用
这很容易解决。 简单地去掉参数和括号会给我们一个参考而不是执行function。
a.replace('f', String.prototype.toUpperCase.apply)
如果您现在尝试运行代码,您将收到一条错误消息,指出 undefined 不是 function,因此无法调用。 这是因为 String.prototype.toUpperCase.apply 实际上是通过 JavaScript 的原型 inheritance 对Function.prototype.apply()的引用。 所以我们实际上在做的看起来更像这样
a.replace('f', Function.prototype.apply)
这显然不是我们的本意。 它怎么知道在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))
最后一个问题是String.prototype.replace()会将几个 arguments 传递给它的替换 function。 但是, Function.prototype.apply()期望第二个参数是一个数组,而是获取一个字符串或数字(取决于您是否使用捕获组)。 这将导致无效的参数列表错误。
幸运的是,我们可以简单地将Function.prototype.call() (它接受任意数量的 arguments,其中没有类型限制)替换为Function.prototype.app 。 我们现在已经到了工作代码!
a.replace(/f/, Function.prototype.call.bind(String.prototype.toUpperCase))
没有人愿意多次键入原型。 相反,我们将利用通过 inheritance 引用相同方法的对象这一事实。 String 构造函数是 function,继承自 Function 的原型。 这意味着我们可以在 String.call 中替换Function.prototype.call (实际上我们可以使用 Date.call 来节省更多字节,但这不太语义)。
我们还可以利用我们的变量“a”,因为它的原型包含对String.prototype.toUpperCase的引用,我们可以将其替换为 a.toUpperCase。 正是上述 3 种解决方案和这些字节节省措施的组合,我们才获得了这篇文章顶部的代码。
旧帖子,但值得扩展 @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.
我只想强调function
的两个参数使查找特定格式和替换格式中的捕获组成为可能。
我们为什么不直接查一下定义呢?
如果我们写:
a.replace(/(f)/, x => x.toUpperCase())
我们不妨说:
a.replace('f','F')
更糟糕的是,我怀疑没有人意识到他们的示例之所以有效,只是因为他们用括号捕获了整个正则表达式。 如果您查看定义,传递给replacer
器 function 的第一个参数实际上是整个匹配模式,而不是您用括号捕获的模式:
function replacer(match, p1, p2, p3, offset, string)
如果要使用箭头 function 表示法:
a.replace(/xxx(yyy)zzz/, (match, p1) => p1.toUpperCase()
解决方案
a.replace(/(f)/,x=>x.toUpperCase())
替换所有出现的 grup 使用/(f)/g
正则表达式。 您的代码中的问题: String.prototype.toUpperCase.apply("$1")
和"$1".toUpperCase()
给出了"$1"
(自己在控制台中尝试) - 所以它不会改变任何东西,实际上你调用a.replace( /(f)/, "$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);
给定一个字典(对象,在这种情况下,一个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 普通 object 并定义 function 以获取 ZA8CFDE6331BD59EB26AC96 的原始字符串匹配的返回匹配属性值
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);
在第一个(左)替换 arg 中使用regexp ()
选择的捕获组被发送到第二个(右)arg,即回调 function 。 x
和y
给出了捕获的字符串(不知道为什么 2 次。)和 index(第三个)给出了引用字符串中捕获组的开头的索引。 因此,可以使用三元运算符在第一次出现时不放置_
。
let str = 'MyStringName'; str = str.replace(/([^a-z0-9])/g, (x,y,index) => { return index?= 0. '_' + x:toLowerCase(). x;toLowerCase(); }). console;log(str);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.