Javascript에 RegExp.escape 함수가 있습니까?


442

가능한 문자열 중에서 정규 표현식을 만들고 싶습니다.

var usersString = "Hello?!*`~World()[]";
var expression = new RegExp(RegExp.escape(usersString))
var matches = "Hello".match(expression);

이를위한 내장 된 방법이 있습니까? 그렇지 않다면 사람들은 무엇을 사용합니까? 루비있다 RegExp.escape. 나는 내 자신을 쓸 필요가 없다고 느끼지 않습니다. 거기에 표준이 있어야합니다. 감사!


15
RegExp.escape현재 진행중인 훌륭한 사람들을 업데이트하고 싶었고 귀중한 의견을 가지고 있다고 생각하는 사람이라면 누구나 참여할 수 있습니다. core-js 및 기타 polyfill이 제공합니다.
Benjamin Gruenbaum

5
이 답변최근 업데이트에 따르면 이 제안은 거부되었습니다. 문제 참조
try-catch-finally

답변:


573

위에 링크 된 기능이 충분하지 않습니다. 문자 그룹에서 범위에 사용되는 ^또는 $(문자열의 시작과 끝) 또는를 이스케이프하지 않습니다 -.

이 기능을 사용하십시오 :

function escapeRegex(string) {
    return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}

언뜻보기에는 불필요하게 보일 수 있지만 이스케이프 -(및 ^)는 문자를 이스케이프하는 데 적합한 기능을 문자 클래스와 정규식 본문에 삽입하는 데 적합합니다.

이스케이프 /기능은 이스케이프 문자가 나중에 평가하기 위해 JS 정규식 리터럴에서 사용되도록 이스케이프 문자에 적합합니다.

둘 중 어느 하나를 피할 수있는 단점이 없으므로 더 넓은 사용 사례를 다루기 위해 탈출하는 것이 좋습니다.

그리고 이것이 표준 JavaScript의 일부가 아니라는 것은 실망스러운 일입니다.


16
실제로, 우리는 탈출 할 필요가 없습니다 /전혀
가시

28
@Paul : Perl quotemeta( \Q), Python re.escape, PHP preg_quote, Ruby Regexp.quote...
bobince

13
루프에서이 기능을 사용하려는 경우, 그것은 그것의 정규 표현식 객체 자신의 변수를 만들기 위해 아마도 최선의 var e = /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g;다음 기능은 return s.replace(e, '\\$&');한 번만 정규식의 인스턴스를 이런 식으로.
styfle

15
내장 객체를 보강하는 것에 대한 표준 주장이 여기에 적용됩니다. 향후 버전의 ECMAScript RegExp.escape에서 구현이 다른 버전을 제공하면 어떻게됩니까 ? 이 기능을 아무 것도 첨부하지 않는 것이 좋을까요?
Mark Amery

15
bobince는 eslint의 의견에 신경 쓰지 않습니다
bobince

114

사람이, lodash을 사용하기 위해 v3.0.0 이후 _.escapeRegExp의 기능이 내장에있다 :

_.escapeRegExp('[lodash](https://lodash.com/)');
// → '\[lodash\]\(https:\/\/lodash\.com\/\)'

그리고 전체 lodash 라이브러리가 필요하지 않은 경우 해당 기능 만 필요할 수 있습니다 !


6
이것의 npm 패키지도 있습니다! npmjs.com/package/lodash.escaperegexp
Ted Pennings

1
이것은 간단한 일을 위해 실제로 거기에있을 필요가없는 많은 코드를 가져옵니다. bobince의 대답을 사용하십시오 ... lodash 버전보다로드 할 바이트가 너무 적습니다!
Rob Evans

6
@RobEvans 내 대답은 "lodash를 사용하는 사람"으로 시작 하며 함수 필요로한다고 언급합니다 escapeRegExp.
gustavohenke

2
@gustavohenke 죄송합니다. 조금 더 명확 해졌습니다. "그 기능에"링크 된 모듈이 포함되어 있습니다. 살펴보면 단일 정규 표현식이있는 단일 함수가되어야하는 것에 대한 코드가 많이 있습니다. 이미 lodash를 사용하고 있다면 동의하는 것이 합리적이지만 다른 대답은 사용하십시오. 불분명 한 의견으로 죄송합니다.
Rob Evans

2
@maddob 나는 당신이 언급 한 \ x3를 볼 수 없다 : 탈출 된 줄이 좋아 보인다, 내가 기대하는 것
Federico Fissore

43

여기에서 대부분의 표현식은 단일 특정 사용 사례를 해결합니다.

괜찮습니다.하지만 "항상 작동"방식을 선호합니다.

function regExpEscape(literal_string) {
    return literal_string.replace(/[-[\]{}()*+!<=:?.\/\\^$|#\s,]/g, '\\$&');
}

정규 표현식에서 다음 용도로 리터럴 문자열을 "완전히 이스케이프"합니다.

  • 정규식에 삽입 예 :new RegExp(regExpEscape(str))
  • 문자 클래스에 삽입 예 :new RegExp('[' + regExpEscape(str) + ']')
  • 정수 카운트 지정자에 삽입 예 :new RegExp('x{1,' + regExpEscape(str) + '}')
  • 비 JavaScript 정규식 엔진에서 실행

다루는 특수 문자 :

  • -: 문자 클래스에서 문자 범위를 만듭니다.
  • [/ ]: 문자 클래스를 시작 / 종료합니다.
  • {/ }: 분자 지정자를 시작 / 종료합니다.
  • (/ ): 그룹을 시작 / 종료합니다.
  • */ +/ ?: 반복 유형을 지정합니다.
  • .: 모든 문자와 일치합니다.
  • \: 문자를 이스케이프하고 엔터티를 시작합니다.
  • ^: 일치 영역의 시작을 지정하고 문자 클래스에서 일치를 무효화합니다.
  • $: 일치 영역의 끝을 지정합니다.
  • |: 교대를 지정합니다.
  • #: 빈 공간 모드에서 주석을 지정합니다.
  • \s: 여유 공간 모드에서는 무시됩니다.
  • ,: 분자 지정자에서 값을 구분합니다.
  • /: 표현식을 시작하거나 종료합니다.
  • :: 특수 그룹 유형과 펄 스타일 문자 클래스의 일부를 완성합니다.
  • !: 폭이 0 인 그룹을 무효화합니다.
  • </ =: 폭이 0 인 그룹 사양의 일부.

노트:

  • /정규 표현의 풍미에 꼭 필요한 것은 아닙니다. 그러나 누군가 (shudder) 가 할 경우를 대비하여 보호합니다 eval("/" + pattern + "/");.
  • , 문자열이 숫자 지정자에서 정수인 경우 자동 컴파일 오류 대신 RegExp 컴파일 오류가 올바르게 발생합니다.
  • #그리고 \s자바 스크립트에서 탈출 할 필요가 있지만, 많은 다른 맛을하지 않습니다. 정규식이 나중에 다른 프로그램으로 전달 될 경우에는 여기서 이스케이프됩니다.

JavaScript 정규식 엔진 기능에 추가 될 가능성에 대비하여 정규 표현식을 미래에 대비해야 할 경우 더 편집증을 사용하는 것이 좋습니다.

function regExpEscapeFuture(literal_string) {
    return literal_string.replace(/[^A-Za-z0-9_]/g, '\\$&');
}

이 함수는 향후 정규 표현식 플레이버에서 구문에 사용되지 않도록 명시 적으로 보장 된 문자를 제외한 모든 문자를 이스케이프합니다.


진정으로 위생을 유지하려면 다음과 같은 경우를 고려하십시오.

var s = '';
new RegExp('(choice1|choice2|' + regExpEscape(s) + ')');

이것은 해야 하지 다른 맛을 자바 스크립트에서 잘 컴파일,하지만 것입니다. 다른 플레이버로 전달하려는 경우 다음과 같이 null 경우를 s === ''독립적으로 확인해야합니다.

var s = '';
new RegExp('(choice1|choice2' + (s ? '|' + regExpEscape(s) : '') + ')');

1
/에서 탈출 할 필요가 없습니다 [...]문자 클래스.
Dan Dascalescu

1
이들 대부분은 탈출 할 필요가 없습니다. "문자 클래스에서 문자 범위를 만듭니다" -문자열 안에 문자 클래스가 없습니다. "자유 공간 모드에서 설명을 지정하고, 자유 공간 모드에서 무시 됨"-Javascript에서 지원되지 않습니다. " 분자 지정자에서 값을 분리합니다" -문자열 내부에서 절대 숫자 지정자에 있지 않습니다. 또한 이름 지정 사양 내에서 임의의 텍스트를 작성할 수 없습니다. "표현 시작 또는 종료" -탈출 할 필요가 없습니다. Eval은 더 많은 탈출이 필요하기 때문에 경우가 아닙니다. [다음 코멘트에서 계속 될 것입니다]
Qwertiy

"특수 그룹 유형과 Perl 스타일 문자 클래스의 일부를 완료하십시오"-Javascript 에서 사용할 수없는 것 같습니다. "제로 폭 그룹, 제로 폭 그룹 사양의 일부를 부정" -문자열 안에 그룹이 없습니다.
Qwertiy

@Qwertiy 이러한 추가 탈출의 이유는 특정 사용 사례에서 문제를 일으킬 수있는 최첨단 사례를 제거하기위한 것입니다. 예를 들어이 함수의 사용자는 이스케이프 된 정규식 문자열을 그룹의 일부로 다른 정규식에 삽입하거나 Javascript 이외의 다른 언어로 사용할 수도 있습니다. 이 함수는 "문자 클래스의 일부가 될 수 없습니다"와 같은 가정을하지 않습니다. 왜냐하면 일반적인 의미이기 때문 입니다. 더 YAGNI 접근 방식은 다른 답변을 참조하십시오.
Pi Marillion

아주 좋아요 왜 _가 이스케이프되지 않습니까? 나중에 정규 표현식 구문이되지 않도록 보장하는 것은 무엇입니까?
madprops

30

정규식에 대한 Mozilla 개발자 네트워크 안내서 는 다음과 같은 이스케이프 기능을 제공합니다.

function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}

@DanDascalescu 당신이 맞아요. MDN 페이지가 업데이트되었으며 =더 이상 포함되지 않습니다.
quietmint

21

jQueryUI의 자동 완성 위젯 (버전 1.9.1)에서는 약간 다른 정규식 (6753 행)을 사용합니다. 다음은 @bobince 접근법과 결합 된 정규식입니다.

RegExp.escape = function( value ) {
     return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
}

4
유일한 차이점은 ,메타 문자가 아닌 이스케이프 및 #자유 간격 모드에서만 중요한 공백 (JavaScript에서 지원되지 않음)입니다. 그러나 그들은 슬래시를 피하지 않는 것이 옳습니다.
마틴 엔더

18
코드를 로컬로 붙여 넣지 않고 jquery UI 구현을 재사용하려면로 이동하십시오 $.ui.autocomplete.escapeRegex(myString).
Scott Stafford

2
lodash도 _. escapeRegExp 및 npmjs.com/package/lodash.escaperegexp
Ted Pennings

v1.12도 마찬가지입니다!
피터 크라우스

13

영숫자가 아닌 모든 문자를 빠져 나가는 것을 막을 수있는 것은 없습니다 :

usersString.replace(/(?=\W)/g, '\\');

당신이 할 때 어느 정도의 가독성을 잃지 re.toString()만 많은 단순성 (및 보안)을 얻습니다.

ECMA-262에 따르면, 한편으로, 정규 표현식 "구문 문자는"영숫자가 아닌 항상 결과가 안전하고, 이스케이프 시퀀스 (그런하다 \d, \w, \n)는 항상 영숫자 같은 거짓 제어 이스케이프는 생성되지 않습니다 것을 .


간단하고 효과적입니다. 나는 이것이 받아 들인 대답보다 훨씬 낫습니다. (실제로) 오래된 브라우저의 .replace(/[^\w]/g, '\\$&')경우 동일한 방식으로 작동합니다.
Tomas Langkaas

6
이것은 유니 코드 모드에서 실패합니다. 예를 들어, 서로 게이트 쌍의 각 코드 단위를 개별적으로 일치시켜 new RegExp('🍎'.replace(/(?=\W)/g, '\\'), 'u')예외 \W이스케이프 코드 가 발생하므로 예외가 발생 합니다.
Alexey Lebedev

1
대안 :.replace(/\W/g, "\\$&");
Miguel Pynto

@AlexeyLebedev 응답이 유니 코드 모드를 처리하도록 수정 되었습니까? 아니면이 단순성을 유지하면서 다른 솔루션이 있습니까?
johny 왜


6

이것은 더 짧은 버전입니다.

RegExp.escape = function(s) {
    return s.replace(/[$-\/?[-^{|}]/g, '\\$&');
}

이것은의 비 메타 문자를 포함 %, &, ', 그리고 ,있지만, 자바 스크립트 정규식 사양이 할 수 있습니다.


2
문자 범위가 문자 목록을 숨기므로이 "짧은"버전을 사용하지 않기 때문에 언뜻보기에 정확성을 확인하기가 더 어렵습니다.
nhahtdh

@nhahtdh 아마 아닐 수도 있지만 정보를 위해 여기에 게시됩니다.
kzh

@kzh : "정보 용"을 게시하면 이해를위한 게시보다 도움이됩니다. 내 대답 이 더 명확 하다는 데 동의하지 않습니까?
Dan Dascalescu

최소한, .놓쳤다. 그리고 (). 아님? [-^이상하다. 나는 거기에 무엇이 있는지 기억하지 못한다.
Qwertiy

그것들은 지정된 범위에 있습니다.
kzh


3

정규 표현식 (예 : 블랙리스트)에 문제를 일으킬 수있는 문자를 이스케이프 처리하는 대신 화이트리스트를 사용하는 것이 좋습니다. 이렇게하면 각 캐릭터가 일치하지 않는 한 오염 된 것으로 간주됩니다.

이 예제에서는 다음 표현식을 가정하십시오.

RegExp.escape('be || ! be');

문자, 숫자 및 공백을 허용합니다.

RegExp.escape = function (string) {
    return string.replace(/([^\w\d\s])/gi, '\\$1');
}

보고:

"be \|\| \! be"

이스케이프 할 필요가없는 캐릭터를 이스케이프 처리 할 수는 있지만 표현을 방해하지는 않습니다.


그의 답변이 @filip의 답변과 다른가요? stackoverflow.com/a/40562456/209942
johny 왜

3
escapeRegExp = function(str) {
  if (str == null) return '';
  return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
};

1

다른 답변의 함수는 전체 정규 표현식을 이스케이프 처리하는 데 과도합니다 ( 나중에 더 큰 정규 표현식으로 연결되는 정규 표현식의 일부 를 이스케이프 처리하는 데 유용 할 수 있음 ).

당신은 전체 정규 표현식을 탈출하거나 독립있는 메타 문자를 인용, 그것으로 완료 (경우 ., ?, +, *, ^, $, |, \무언가를) 또는 시작 ( (, [, {) 당신이 필요로하는 모든 것입니다 :

String.prototype.regexEscape = function regexEscape() {
  return this.replace(/[.?+*^$|({[\\]/g, '\\$&');
};

그리고 그렇습니다. JavaScript에는 이와 같은 기능이 내장되어 있지 않습니다.


사용자 입력을 이스케이프하고 + input + (text)next에 삽입 한다고 가정 해 봅시다 . 메소드는 컴파일에 실패한 결과 문자열 을 제공합니다 . 참고이 꽤 합리적인 삽입, 좋아하지 어떤 미친 하나입니다 + 입력 + (이 경우, 프로그래머가 바보 같은 일을 비난 할 수 있습니다)(?:)(?:\(text)next)re\re
nhahtdh

1
@nhahtdh : 내 대답은 정규 표현식의 일부 (또는 미래의 부분)가 아니라 정규 표현식 전체를 빠져 나와 "완료"하는 것을 구체적으로 언급했습니다. downvote를 친절하게 취소 하시겠습니까?
Dan Dascalescu

전체 표현식을 이스케이프 처리하는 경우는 거의 없습니다. 문자열 연산이 있습니다. 리터럴 문자열로 작업하려는 경우 정규식보다 훨씬 빠릅니다.
nhahtdh

이것은 부정확하다고 언급하지는 않습니다 . \정규 표현식이 그대로 \w남아 있기 때문에 탈출해야합니다 . 또한 JavaScript는 후행을 허용하지 않는 것 같습니다 ). 최소한 Firefox에서 오류가 발생합니다.
nhahtdh

1
폐쇄에 대한 부분을 해결하십시오)
nhahtdh

1

또 다른 (훨씬 더 안전한) 접근법은 유니 코드 이스케이프 형식을 사용하여 모든 문자 (현재 우리가 아는 몇 가지 특수 문자가 아닌)를 이스케이프 처리하는 것입니다 \u{code}.

function escapeRegExp(text) {
    return Array.from(text)
           .map(char => `\\u{${char.charCodeAt(0).toString(16)}}`)
           .join('');
}

console.log(escapeRegExp('a.b')); // '\u{61}\u{2e}\u{62}'

u이 메소드가 작동 하려면 플래그 를 전달해야합니다 .

var expression = new RegExp(escapeRegExp(usersString), 'u');

1


리터럴로 간주 되기 위해 탈출해야 할 메타 문자는 12 개뿐입니다 .

균형 잡힌
정규식 래퍼에 삽입되고 추가 된 이스케이프 된 문자열로 수행 된 작업은 중요하지 않습니다.

이것을 사용하여 문자열을 바꾸십시오.

var escaped_string = oldstring.replace( /[\\^$.|?*+()[{]/g, '\\$&' );

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