JavaScript에서 정규식 리터럴을 어떻게 연결할 수 있습니까?


145

이런 식으로 할 수 있습니까?

var pattern = /some regex segment/ + /* comment here */
    /another segment/;

아니면 새로운 RegExp()구문 을 사용 하고 문자열을 연결해야합니까? 코드가 더 자명하고 간결하므로 리터럴을 사용하고 싶습니다.


2
그것은 당신이 String.raw를 (사용하는 경우) 탈출 정규식 문자를 처리하는 것이 더 쉽습니다 :let regexSegment1 = String.raw`\s*hello\s*`
iono

답변:


190

다음은 정규 표현식 리터럴 구문을 사용하지 않고 정규 표현식을 작성하는 방법입니다. 이를 통해 임의의 문자열 조작이 정규식 오브젝트가되기 전에 수행 할 수 있습니다.

var segment_part = "some bit of the regexp";
var pattern = new RegExp("some regex segment" + /*comment here */
              segment_part + /* that was defined just now */
              "another segment");

정규 표현식 리터럴이 두 개인 경우 실제로이 기술을 사용하여 연결할 수 있습니다.

var regex1 = /foo/g;
var regex2 = /bar/y;
var flags = (regex1.flags + regex2.flags).split("").sort().join("").replace(/(.)(?=.*\1)/g, "");
var regex3 = new RegExp(expression_one.source + expression_two.source, flags);
// regex3 is now /foobar/gy

리터럴 정규 표현식 대신 표현식 1과 2를 리터럴 문자열로 사용하는 것보다 훨씬 중요합니다.


2
이 방법을 사용할 때 각 세그먼트는 유효한 정규식이어야합니다. new RegExp(/(/.source + /.*/.source + /)?/.source);작동하지 않는 등의 표현식을 구성하십시오 .
Sam

이 솔루션은 백 매치 그룹의 경우 작동하지 않습니다. 이 경우 작동하는 솔루션에 대한 내 대답을 참조하십시오.
Mikaël Mayer

문자를 이스케이프해야하는 경우 이중 백 슬래시를 사용하십시오. new Regexp ( '\\ $'+ "flum")
Jeff Lowery

"<regexp> .flags"를 사용해야하는 경우 플래그에 액세스 할 수 있으므로 이론적으로도 플래그를 결합 할 수 있습니다.
bnunamak

어디 expression_one에서 왔어요 ? 당신은 의미 regex1합니까?
TallOrderDev

30

정규 표현식 객체를 무작위로 연결하면 부작용이 발생할 수 있습니다. 대신 RegExp.source 를 사용하십시오 .

var r1 = /abc/g;
var r2 = /def/;
var r3 = new RegExp(r1.source + r2.source, 
                   (r1.global ? 'g' : '') 
                   + (r1.ignoreCase ? 'i' : '') + 
                   (r1.multiline ? 'm' : ''));
console.log(r3);
var m = 'test that abcdef and abcdef has a match?'.match(r3);
console.log(m);
// m should contain 2 matches

또한 표준 RegExp 플래그를 사용하여 이전 RegExp의 정규식 플래그를 유지할 수 있습니다.

jsFiddle


이것은 다음을 사용하여 개선 될 수 있습니다RegExp.prototype.flags
Dmitry Parzhitsky

19

"eval"옵션에 동의하지 않습니다.

var xxx = /abcd/;
var yyy = /efgh/;
var zzz = new RegExp(eval(xxx)+eval(yyy));

의도 한 결과가 아닌 "// abcd // efgh //"를 제공합니다.

같은 소스를 사용하여

var zzz = new RegExp(xxx.source+yyy.source);

"/ abcdefgh /"를 제공하고 맞습니다.

논리적으로 평가할 필요가 없습니다. EXPRESSION을 알고 있습니다. 당신은 그것의 소스가 필요하거나 그것이 어떻게 가치를 쓰지 않는지에 대해 설명합니다. 플래그는 RegExp의 선택적 인수 만 사용하면됩니다.

내 상황에서 나는 함께 연결하려고 여러 표현에 사용되는 ^와 $의 문제를 겪고 있습니다! 이러한 표현은 프로그램 전체에서 사용되는 문법 필터입니다. 이제 나는 그들 중 일부를 PREPOSITIONS의 경우를 처리하기 위해 함께 사용하고 싶지 않습니다. 시작과 끝을 제거하기 위해 소스를 "슬라이스"해야 할 수도 있습니다. ^ (and / or) $ :) Cheers, Alex.


나는 소스 속성의 사용을 좋아합니다. 나처럼-jslint를 사용하면 다음과 같이하면 잔소리가됩니다.var regex = "\.\..*"
Nils-o-mat

7

문제 정규식에 \ 1과 같은 역 일치 그룹이 포함 된 경우.

var r = /(a|b)\1/  // Matches aa, bb but nothing else.
var p = /(c|d)\1/   // Matches cc, dd but nothing else.

그런 다음 소스를 오염시키는 것은 효과가 없습니다. 실제로이 둘의 조합은 다음과 같습니다.

var rp = /(a|b)\1(c|d)\1/
rp.test("aadd") // Returns false

해결책 : 먼저 첫 번째 정규 표현식에서 일치하는 그룹 수를 계산 한 다음 두 번째 일치하는 각 토큰에 대해 일치하는 그룹 수만큼 증가시킵니다.

function concatenate(r1, r2) {
  var count = function(r, str) {
    return str.match(r).length;
  }
  var numberGroups = /([^\\]|^)(?=\((?!\?:))/g; // Home-made regexp to count groups.
  var offset = count(numberGroups, r1.source);    
  var escapedMatch = /[\\](?:(\d+)|.)/g;        // Home-made regexp for escaped literals, greedy on numbers.
  var r2newSource = r2.source.replace(escapedMatch, function(match, number) { return number?"\\"+(number-0+offset):match; });
  return new RegExp(r1.source+r2newSource,
      (r1.global ? 'g' : '') 
      + (r1.ignoreCase ? 'i' : '')
      + (r1.multiline ? 'm' : ''));
}

테스트:

var rp = concatenate(r, p) // returns  /(a|b)\1(c|d)\2/
rp.test("aadd") // Returns true

2
예 (여기서는 수정하지 않습니다). 이 기능은 연관성이 있으므로 다음 코드를 사용할 수 있습니다.function concatenateList() { var res = arguments[0]; for(var i = 1; i < arguments.length; i++) { res = concatenate(res, arguments[i]); } return res; }
Mikaël Mayer

3

리터럴 구문을 가능한 자주 사용하는 것이 좋습니다. 더 짧고 가독성이 좋으며 이스케이프 따옴표 나 이중 이스케이프가 필요하지 않습니다. "Javascript Patterns"에서 Stoyan Stefanov 2010.

그러나 New를 사용하는 것이 연결하는 유일한 방법 일 수 있습니다.

나는 평가를 피할 것이다. 안전하지 않습니다.


1
나는 복잡한 정규 표현식이 질문 에서처럼 분류되고 주석 처리 될 때 더 읽기 쉽다고 생각합니다.
Sam

3

제공하는:

  • 정규 표현식에서 무엇을하는지 알고 있습니다.
  • 패턴을 형성하기 위해 많은 정규 표현식이 있으며 동일한 플래그를 사용합니다.
  • 작은 패턴 청크를 배열로 분리하는 것이 더 읽기 쉽습니다.
  • 또한 다음 개발자 나 자신을 위해 각 부분에 주석을 달 수 있기를 원합니다.
  • 정규식 /this/g대신 시각적으로 단순화하는 것을 선호합니다 new RegExp('this', 'g').
  • 정규식을 처음부터 한 조각으로 묶지 않고 추가 단계로 조립하는 것이 좋습니다.

그런 다음 다음과 같이 작성하십시오.

var regexParts =
    [
        /\b(\d+|null)\b/,// Some comments.
        /\b(true|false)\b/,
        /\b(new|getElementsBy(?:Tag|Class|)Name|arguments|getElementById|if|else|do|null|return|case|default|function|typeof|undefined|instanceof|this|document|window|while|for|switch|in|break|continue|length|var|(?:clear|set)(?:Timeout|Interval))(?=\W)/,
        /(\$|jQuery)/,
        /many more patterns/
    ],
    regexString  = regexParts.map(function(x){return x.source}).join('|'),
    regexPattern = new RegExp(regexString, 'g');

그런 다음 다음과 같은 작업을 수행 할 수 있습니다.

string.replace(regexPattern, function()
{
    var m = arguments,
        Class = '';

    switch(true)
    {
        // Numbers and 'null'.
        case (Boolean)(m[1]):
            m = m[1];
            Class = 'number';
            break;

        // True or False.
        case (Boolean)(m[2]):
            m = m[2];
            Class = 'bool';
            break;

        // True or False.
        case (Boolean)(m[3]):
            m = m[3];
            Class = 'keyword';
            break;

        // $ or 'jQuery'.
        case (Boolean)(m[4]):
            m = m[4];
            Class = 'dollar';
            break;

        // More cases...
    }

    return '<span class="' + Class + '">' + m + '</span>';
})

내 특별한 경우 (코드 미러와 같은 편집기), 표현식을 래핑하기 위해 html 태그로 바꿀 때마다 다음과 같은 많은 대체 대신 하나의 큰 정규 표현식을 수행하는 것이 훨씬 쉽습니다. html 태그 자체에 영향을 미치지 않고 (아마도 자바 스크립트에서 지원되지 않는 좋은 외형 없이) 타겟팅하기가 더 어렵습니다 .

.replace(/(\b\d+|null\b)/g, '<span class="number">$1</span>')
.replace(/(\btrue|false\b)/g, '<span class="bool">$1</span>')
.replace(/\b(new|getElementsBy(?:Tag|Class|)Name|arguments|getElementById|if|else|do|null|return|case|default|function|typeof|undefined|instanceof|this|document|window|while|for|switch|in|break|continue|var|(?:clear|set)(?:Timeout|Interval))(?=\W)/g, '<span class="keyword">$1</span>')
.replace(/\$/g, '<span class="dollar">$</span>')
.replace(/([\[\](){}.:;,+\-?=])/g, '<span class="ponctuation">$1</span>')

2

당신은 다음과 같은 것을 할 수 있습니다 :

function concatRegex(...segments) {
  return new RegExp(segments.join(''));
}

세그먼트는 별도의 인수로 전달 된 정규식 리터럴이 아닌 문자열입니다.


1

아니요, 리터럴 방식은 지원되지 않습니다. RegExp를 사용해야합니다.


1

매개 변수가 2 개인 생성자를 사용하고 후행 '/'의 문제점을 피하십시오.

var re_final = new RegExp("\\" + ".", "g");    // constructor can have 2 params!
console.log("...finally".replace(re_final, "!") + "\n" + re_final + 
    " works as expected...");                  // !!!finally works as expected

                         // meanwhile

re_final = new RegExp("\\" + "." + "g");              // appends final '/'
console.log("... finally".replace(re_final, "!"));    // ...finally
console.log(re_final, "does not work!");              // does not work

1

리터럴 클래스와 RegExp 클래스에서 정규식 소스를 연결할 수 있습니다.

var xxx = new RegExp(/abcd/);
var zzz = new RegExp(xxx.source + /efgh/.source);

1

나에게 더 쉬운 방법은 소스를 연결하는 것입니다.

a = /\d+/
b = /\w+/
c = new RegExp(a.source + b.source)

c 값은 다음과 같습니다.

/ \ d + \ w + /


-2

내가 사용하는 것을 선호 eval('your expression')가 추가되지 않기 때문에 /양쪽 끝에 않습니다./='new RegExp'

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