簡體   English   中英

在 Javascript 中用大寫替換正則表達式捕獲組

[英]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 錯了,這個新的巫毒是什么?

問題 1

如前所述,您試圖將調用方法的結果作為String.prototype.replace()的第二個參數傳遞,而您應該傳遞對 function 的引用

解決方案 1

這很容易解決。 簡單地去掉參數和括號會給我們一個參考而不是執行function。

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

問題 2

如果您現在嘗試運行代碼,您將收到一條錯誤消息,指出 undefined 不是 function,因此無法調用。 這是因為 String.prototype.toUpperCase.apply 實際上是通過 JavaScript 的原型 inheritance 對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()會將幾個 arguments 傳遞給它的替換 function。 但是, Function.prototype.apply()期望第二個參數是一個數組,而是獲取一個字符串或數字(取決於您是否使用捕獲組)。 這將導致無效的參數列表錯誤。

解決方案 3

幸運的是,我們可以簡單地將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);

在從 CamelCase 到 bash_case 的字符串轉換(即:對於文件名)的情況下,使用帶有三元運算符的回調。

在第一個(左)替換 arg 中使用regexp ()選擇的捕獲組被發送到第二個(右)arg,即回調 function xy給出了捕獲的字符串(不知道為什么 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM