programing

Javascript에서 Regex 캡처 그룹을 대문자로 바꾸기

nasanasas 2020. 11. 10. 08:16
반응형

Javascript에서 Regex 캡처 그룹을 대문자로 바꾸기


캡처 그룹을 JavaScript에서 대문자로 바꾸는 방법을 알고 싶습니다. 지금까지 시도했지만 작동하지 않는 단순화 된 버전은 다음과 같습니다.

> a="foobar"
'foobar'
> a.replace( /(f)/, "$1".toUpperCase() )
'foobar'
> a.replace( /(f)/, String.prototype.toUpperCase.apply("$1") )
'foobar'

이 코드의 문제점을 설명해 주시겠습니까?


에 함수를 전달할 수 있습니다 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"))

믿거 나 말거나이 표현의 의미는 정확히 동일합니다.


나는 내가 파티에 늦었다는 것을 알고 있지만 여기에 초기 시도의 라인을 따라 더 짧은 방법이 있습니다.

a.replace('f', String.call.bind(a.toUpperCase));

그래서 당신은 어디로 잘못 갔고이 새로운 부두는 무엇입니까?

문제 1

앞에서 언급했듯이 호출 된 메서드의 결과를 String.prototype.replace () 의 두 번째 매개 변수로 전달하려고했지만 대신 함수에 대한 참조를 전달해야합니다.

해결책 1

해결하기 쉽습니다. 단순히 매개 변수와 괄호를 제거하면 함수를 실행하는 대신 참조를 얻을 수 있습니다.

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

문제 2

지금 코드를 실행하려고하면 undefined는 함수가 아니므로 호출 할 수 없다는 오류가 표시됩니다. 이는 String.prototype.toUpperCase.apply가 실제로 JavaScript의 프로토 타입 상속을 통해 Function.prototype.apply ()에 대한 참조이기 때문 입니다. 그래서 우리가 실제로하는 것은 다음과 같습니다.

a.replace('f', Function.prototype.apply)

분명히 우리가 의도 한 것이 아닙니다. String.prototype.toUpperCase () 에서 Function.prototype.apply () 를 실행하는 방법을 어떻게 알 수 있습니까?

해결 방법 2

Function.prototype.bind ()를 사용하여 컨텍스트가 String.prototype.toUpperCase로 특별히 설정된 Function.prototype.call의 복사본을 만들 수 있습니다. 이제 다음이 있습니다.

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

문제 3

마지막 문제는 String.prototype.replace () 가 대체 함수에 여러 인수를 전달 한다는 것입니다. 그러나 Function.prototype.apply () 는 두 번째 매개 변수가 배열 일 것으로 예상하지만 대신 문자열 또는 숫자를 가져옵니다 (캡처 그룹을 사용하는지 여부에 따라 다름). 이로 인해 잘못된 인수 목록 오류가 발생합니다.

해결책 3

운 좋게도 Function.prototype.call ()을 간단히 Function.prototype.apply ()으로 대체 할 수 있습니다 (어떤 수의 인수도 허용하지만 유형 제한이 없음 ) . 이제 작업 코드에 도달했습니다!

a.replace(/f/, Function.prototype.call.bind(String.prototype.toUpperCase))

흘리는 바이트!

Nobody wants to type prototype a 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).

We can also leverage our variable 'a' since it's prototype includes a reference to String.prototype.toUpperCase we 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.


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.


SOLUTION

a.replace(/(f)/,x=>x.toUpperCase())  

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).

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);


Given a dictionary (object, in this case, a Map) of property, values, and using .bind() as described at answers

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);

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

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);

참고URL : https://stackoverflow.com/questions/6142922/replace-a-regex-capture-group-with-uppercase-in-javascript

반응형