198 Stimmen

Wie kann ich Regex-Literale in JavaScript verketten?

Ist es möglich, so etwas zu tun?

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

Oder muss ich neue RegExp() Syntax und Verkettung einer Zeichenkette? Ich würde es vorziehen, das Literal zu verwenden, da der Code sowohl selbsterklärend als auch prägnant ist.

3 Stimmen

Es ist einfacher, mit escapeten Regex-Zeichen umzugehen, wenn Sie String.raw() verwenden: let regexSegment1 = String.raw`\s*hello\s*`

228voto

Jerub Punkte 40038

Hier erfahren Sie, wie Sie einen regulären Ausdruck erstellen können, ohne die Literal-Syntax für reguläre Ausdrücke zu verwenden. So können Sie eine beliebige Zeichenkettenmanipulation vornehmen, bevor sie zu einem Objekt für reguläre Ausdrücke wird:

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

Wenn Sie zwei reguläre Ausdrucksliterale haben, können Sie sie mit dieser Technik tatsächlich verketten:

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

Es ist einfach wortreicher, als wenn die Ausdrücke eins und zwei buchstabengetreue Zeichenketten anstelle von buchstabengetreuen regulären Ausdrücken sind.

2 Stimmen

Denken Sie daran, dass jedes Segment ein gültiger regulärer Ausdruck sein muss, wenn Sie diesen Ansatz verwenden. Das Konstruieren eines Ausdrucks wie new RegExp(/(/.source + /.*/.source + /)?/.source); scheint nicht zu funktionieren.

0 Stimmen

Diese Lösung funktioniert nicht, wenn es sich um rückwärtsgerichtete Gruppen handelt. Siehe meine Antwort für eine funktionierende Lösung in diesem Fall.

0 Stimmen

Wenn Sie ein Zeichen escapen müssen, dann verwenden Sie doppelte Backslashes: new Regexp(' \\ $' + "flum")

46voto

Japheth Salva Punkte 403

Reguläre Ausdrücke zufällig aneinanderreihen Objekte kann einige unerwünschte Nebeneffekte haben. Verwenden Sie die RegExp.Quelle stattdessen:

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

Dadurch haben Sie auch die Möglichkeit, die Flags eines regulären Ausdrucks aus einem früheren RegExp mit den Standard-RegExp-Flags beizubehalten.

jsFiddle

1 Stimmen

Dies kann verbessert werden durch RegExp.prototype.flags

23voto

Alex Punkte 201

Ich bin nicht ganz einverstanden mit der Option "eval".

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

ergibt "//abcd//efgh//", was nicht das gewünschte Ergebnis ist.

Mit Quellen wie

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

ergibt "/abcdefgh/" und das ist richtig.

Logischerweise ist es nicht nötig, zu bewerten, denn Sie kennen Ihren AUSDRUCK. Sie brauchen nur seine QUELLE oder wie er geschrieben ist, nicht unbedingt seinen Wert. Was die Flags betrifft, so müssen Sie nur das optionale Argument von RegExp verwenden.

In meiner Situation habe ich das Problem, dass ^ und $ in mehreren Ausdrücken verwendet werden, die ich miteinander zu verknüpfen versuche! Diese Ausdrücke sind Grammatikfilter, die im gesamten Programm verwendet werden. Nun möchte ich einige von ihnen zusammen verwenden, um den Fall von PREPOSITIONS zu behandeln. Vielleicht muss ich die Quellen "zerschneiden", um den Anfang und das Ende von ^( und/oder )$ zu entfernen :) Vielen Dank, Alex.

0 Stimmen

Mir gefällt die Verwendung der Quelleigenschaft. Wenn Sie - wie ich - jslint verwenden, wird es nörgeln, wenn Sie etwas wie dies tun: var regex = "\.\..*"

9voto

Mikaël Mayer Punkte 9501

Problem Wenn die Regexp rückwärts übereinstimmende Gruppen enthält wie \1.

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

Dann wird das bloße Aneinanderreihen der Quellen nicht funktionieren. In der Tat, die Kombination der beiden ist:

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

Die Lösung: Zunächst wird die Anzahl der übereinstimmenden Gruppen in der ersten Regex gezählt. Dann wird für jedes rückübereinstimmende Token in der zweiten Regex die Anzahl der übereinstimmenden Gruppen erhöht.

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' : ''));
}

Test:

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

2 Stimmen

Ja (ich werde es hier allerdings nicht ändern). Diese Funktion ist assoziativ, so dass Sie den folgenden Code verwenden können: function concatenateList() { var res = arguments[0]; for(var i = 1; i < arguments.length; i++) { res = concatenate(res, arguments[i]); } return res; }

6voto

antoni Punkte 4235

Vorausgesetzt, dass:

  • Sie wissen, was Sie in Ihrer Regexp tun;
  • Sie haben viele Regex-Teile, um ein Muster zu bilden, und sie verwenden dasselbe Flag;
  • Sie finden es übersichtlicher, wenn Sie Ihre kleinen Musterbausteine in ein Array aufteilen;
  • Sie wollen auch in der Lage sein, jeden Teil für den nächsten Entwickler oder für sich selbst später zu kommentieren;
  • Sie es vorziehen, Ihre Regex visuell zu vereinfachen wie /this/g statt new RegExp('this', 'g') ;
  • ist es in Ordnung, wenn Sie die Regex in einem zusätzlichen Schritt zusammensetzen, anstatt sie von Anfang an in einem Stück zu haben;

Dann möchten Sie vielleicht so schreiben:

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

können Sie dann etwas tun wie:

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

In meinem speziellen Fall (ein Code-Spiegel-ähnlicher Editor) ist es viel einfacher, eine große Regex auszuführen, als eine Menge Ersetzungen wie die folgenden, da jedes Mal, wenn ich mit einem html-Tag ersetzen, um einen Ausdruck zu umschließen, das nächste Muster schwieriger zu zielen, ohne das html-Tag selbst zu beeinflussen (und ohne die gute zurückblicken die leider nicht in Javascript unterstützt wird):

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X