[javascript] 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))

흘리는 바이트!

아무도 프로토 타입 을 여러 번 타이핑 하고 싶어하지 않습니다 . 대신 상속을 통해 동일한 메서드를 참조하는 객체가 있다는 사실을 활용합니다. 함수 인 String 생성자는 Function의 프로토 타입에서 상속됩니다. 이는 String.call에서 Function.prototype.call을 대체 할 수 있음을 의미합니다 (실제로 Date.call을 사용하여 더 많은 바이트를 절약 할 수 있지만 의미가 적습니다).

프로토 타입에 String.prototype.toUpperCase에 대한 참조가 포함되어 있기 때문에 변수 ‘a’를 활용할 수도 있습니다. a.toUpperCase로 바꿀 수 있습니다. 위의 세 가지 솔루션과 이러한 바이트 절약 조치의 조합이이 게시물의 맨 위에있는 코드를 얻는 방법입니다.


답변

이전 게시물이지만 더 제한된 RegEx를 사용하여 다른 사용 사례에 대해 @ChaosPandion 답변을 확장하는 것이 좋습니다. 예를 들어 (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 replacer(match, p1, p2, p3, offset, string)

화살표 기능 표기법을 사용하려는 경우 :

a.replace(/xxx(yyy)zzz/, (match, p1) => p1.toUpperCase()


답변

해결책

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

모든 grup 발생을 바꾸려면 /(f)/gregexp를 사용하십시오 . 코드에서 문제 : String.prototype.toUpperCase.apply("$1")"$1".toUpperCase()제공 "$1"(스스로 콘솔에서 시도) – 변경 아무것도하지 너무 사실 당신은 두 번 호출하지 a.replace( /(f)/, "$1")(이 또한 변경 아무것도).


답변

답변에 설명 된대로 Map속성, 값 및 사용에 대한 사전 (객체,이 경우 a ) 이 주어집니다..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);


답변