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


81

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

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

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


@Erik은 질문의 구성 요소를 제거하지 않습니다. 내 코드가 왜 실패하는지 알고 싶습니다.
Evan Carroll

에반, 나는 당신의 질문을 존중한다고 생각했습니다. 불필요 해 보이는 것만 제거했습니다. 당신이 시도한 코드를 제공했지만 분명히 작동하지 않았기 때문에 사람들은 당신이 그렇게 말할 필요없이 (그리고 어색하게) 이유에 대한 설명이 필요하다는 것을 암시 적으로 알고있었습니다. 그냥 도와 주려고! :)
ErikE

1
에반, 그게 더 낫지? 성가 시려는 뜻은 아닙니다. 다시 롤백하면 다시 편집하지 않지만 최소한 제목 및 태그 편집을 그대로 유지할 수 있습니까?
ErikE

기술적으로 저는 Javascript를 전혀 사용하지 않고 v8 (ECMAScript)을 사용하고 있습니다. 그러나 나는 이것을 검색하는 대부분의 사람들이 JavaScript를 찾을 것이라고 생각하므로 나는 그것에 능숙합니다.
Evan Carroll

1
태그가 속한다고 생각되면 자유롭게 다시 추가하십시오.
ErikE

답변:


159

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

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


@Evan Carroll : 내 대답을 참조하십시오.
kay

4
아, 무슨 말인지 알 겠어요. "\ $ 1"라고 말하고 있어요. 교체하는 부두의 결과는 분명히 $1첫 번째 캡처 그룹을 대체 합니다.
Evan Carroll

@EvanCarroll은 초기 코드가 작동하지 않은 이유와 작동 방법에 대한 자세한 설명은 아래 내 대답을 참조하십시오.
Joshua Piccari 2014 년

15

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

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로 바꿀 수 있습니다. 위의 세 가지 솔루션과 이러한 바이트 절약 조치의 조합이이 게시물의 맨 위에있는 코드를 얻는 방법입니다.


4
더 명확한 솔루션에 대한 설명 페이지를 요구하는 방식으로 코드를 숨기면서 8자를 저장했습니다. 나는 이것이 승리라고 확신하지 않는다.
Lawrence Dol

1
지적 적으로 이것은 자바 스크립트 기능에 대해 한두 가지를 드러내고 가르친다는 점에서 훌륭한 솔루션입니다. 그러나 나는 실제로 사용하기에는 너무 모호하다는 Lawrence와 함께 있습니다. 여전히 멋지다.
meetamit

9

이전 게시물이지만 더 제한된 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특정 형식을 찾고 가능한 형식 내에서 캡처 그룹을 대체하는 두 가지 매개 변수를 강조하고 싶습니다 .


감사합니다! 이전 게시물은 OP의 코드가 작동하지 않는지 에 대한 문제에 대해 답한 것 같습니다 .
Auspex

교체 기능에 오류가 있다고 생각하지만 이것에 대해 확인하십시오. 나는 그것이 있어야한다고 생각합니다 . 첫 번째 논쟁은 return $0.replace($0, $1.toUpperCase())어디에 있습니까$0
Mike는

문자열 교체를위한 간단한 문자열이었습니다. 그래서 f에서 F가 맞습니다.
CallMeLaNN

이것은 괄호 안의 무언가를 바꾸려고 할 때 정말 유용합니다!
Diode Dan

3

정의를 찾아 보지 그래요?

우리가 쓰면 :

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

1

해결책

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

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


0

답변에 설명 된대로 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);

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.