it-swarm.com.de

RegEx für das passende Taskwarrior-Datenformat

Ich versuche die folgende Art von Zeichenfolge zu analysieren:

[key:"val" key2:"val2"]

wo es willkürliche Schlüssel gibt: "val" Paare im Inneren. Ich möchte den Schlüsselnamen und den Wert erfassen. Für die Neugierigen versuche ich das Datenbankformat von Task Warrior zu analysieren.

Hier ist mein Teststring:

[description:"aoeu" uuid:"123sth"]

damit soll hervorgehoben werden, dass sich in einem Schlüssel oder Wert außer Leerzeichen keine Leerzeichen um die Doppelpunkte befinden können und die Werte immer in doppelten Anführungszeichen stehen.

Im Knoten ist dies meine Ausgabe:

[deuteronomy][gatlin][~]$ node
> var re = /^\[(?:(.+?):"(.+?)"\s*)+\]$/g
> re.exec('[description:"aoeu" uuid:"123sth"]');
[ '[description:"aoeu" uuid:"123sth"]',
  'uuid',
  '123sth',
  index: 0,
  input: '[description:"aoeu" uuid:"123sth"]' ]

Aber description:"aoeu" passt auch zu diesem Muster. Wie kann ich alle Matches zurückbekommen?

151
gatlin

Rufe re.exec(s) in einer Schleife weiter auf, um alle Übereinstimmungen zu erhalten:

var re = /\s*([^[:]+):\"([^"]+)"/g;
var s = '[description:"aoeu" uuid:"123sth"]';
var m;

do {
    m = re.exec(s);
    if (m) {
        console.log(m[1], m[2]);
    }
} while (m);

Versuchen Sie es mit dieser JSFiddle: https://jsfiddle.net/7yS2V/

202
lawnsea

str.match(pattern) gibt alle Übereinstimmungen als Array zurück, wenn pattern das globale Flag g hat.

Beispielsweise:

const str = 'All of us except @Emran, @Raju and @Noman was there';
console.log(
  str.match(/@\w*/g)
);
// Will log ["@Emran", "@Raju", "@Noman"]
96
Anis

Um alle Übereinstimmungen durchzugehen, können Sie die Funktion replace verwenden:

var re = /\s*([^[:]+):\"([^"]+)"/g;
var s = '[description:"aoeu" uuid:"123sth"]';

s.replace(re, function(match, g1, g2) { console.log(g1, g2); });
84
Christophe

Das ist eine Lösung

var s = '[description:"aoeu" uuid:"123sth"]';

var re = /\s*([^[:]+):\"([^"]+)"/g;
var m;
while (m = re.exec(s)) {
  console.log(m[1], m[2]);
}

Dies basiert auf der Antwort von lawnsea, ist aber kürzer.

Beachten Sie, dass das Flag "g" gesetzt sein muss, um den internen Zeiger über Aufrufe hinweg vorwärts zu bewegen.

54
lovasoa
str.match(/regex/g)

gibt alle Übereinstimmungen als Array zurück.

Wenn Sie aus mysteriösen Gründen die zusätzlichen Informationen benötigen, die mit exec geliefert werden, können Sie dies alternativ zu den vorherigen Antworten auch mit einer rekursiven Funktion anstelle einer Schleife tun (was auch cooler aussieht).

function findMatches(regex, str, matches = []) {
   const res = regex.exec(str)
   res && matches.Push(res) && findMatches(regex, str, matches)
   return matches
}

// Usage
const matches = findMatches(/regex/g, str)

wie bereits in den Kommentaren erwähnt, ist es wichtig, dass g am Ende der Regex-Definition steht, um den Zeiger bei jeder Ausführung vorwärts zu bewegen.

14
noego

Basierend auf der Funktion von Agus, aber ich ziehe es vor, nur die Übereinstimmungswerte zurückzugeben:

var bob = "> bob <";
function matchAll(str, regex) {
    var res = [];
    var m;
    if (regex.global) {
        while (m = regex.exec(str)) {
            res.Push(m[1]);
        }
    } else {
        if (m = regex.exec(str)) {
            res.Push(m[1]);
        }
    }
    return res;
}
var Amatch = matchAll(bob, /(&.*?;)/g);
console.log(Amatch);  // yeilds: [>, <]
9
bob

Iterables sind schöner:

const matches = (text, pattern) => ({
  [Symbol.iterator]: function * () {
    const clone = new RegExp(pattern.source, pattern.flags);
    let match = null;
    do {
      match = clone.exec(text);
      if (match) {
        yield match;
      }
    } while (match);
  }
});

Verwendung in einer Schleife:

for (const match of matches('abcdefabcdef', /ab/g)) {
  console.log(match);
}

Oder wenn Sie ein Array wollen:

[ ...matches('abcdefabcdef', /ab/g) ]
7
sdgfsdh

Wir sehen endlich eine eingebaute matchAll -Funktion, siehe hier für die Beschreibung und Kompatibilitätstabelle . Es sieht aus wie ab April 2019, Chrome und Firefox werden unterstützt, aber nicht IE, Edge, Opera oder Node.js. Scheint so, als wäre es erstellt im Dezember 2018 Geben Sie also etwas Zeit, um alle Browser zu erreichen, aber ich vertraue darauf, dass es dort ankommt.

Die integrierte Funktion matchAll ist Nice, da sie ein iterables zurückgibt. Es gibt auch Erfassungsgruppen für jedes Match zurück! So können Sie Dinge wie tun

// get the letters before and after "o"
let matches = "stackoverflow".matchAll(/(\w)o(\w)/g);

for (match of matches) {
    console.log("letter before:" + match[1]);
    console.log("letter after:" + match[2]);
}

arrayOfAllMatches = [...matches]; // you can also turn the iterable into an array

Anscheinend verwendet jedes Übereinstimmungsobjekt dasselbe Format wie match() . Jedes Objekt ist also ein Array der Übereinstimmungs- und Erfassungsgruppen, zusammen mit drei zusätzlichen Eigenschaften index, input und groups. So sieht es aus:

[<match>, <group1>, <group2>, ..., index: <match offset>, input: <original string>, groups: <named capture groups>]

Für weitere Informationen zu matchAll gibt es auch eine Google-Entwicklerseite . Es gibt auch Polyfills/Shims zur Verfügung.

6
woojoo666

Hier ist meine Funktion, um die Übereinstimmungen zu erhalten:

function getAllMatches(regex, text) {
    if (regex.constructor !== RegExp) {
        throw new Error('not RegExp');
    }

    var res = [];
    var match = null;

    if (regex.global) {
        while (match = regex.exec(text)) {
            res.Push(match);
        }
    }
    else {
        if (match = regex.exec(text)) {
            res.Push(match);
        }
    }

    return res;
}

var regex = /abc|def|ghi/g;
var res = getAllMatches(regex, 'abcdefghi');

res.forEach(function (item) {
    console.log(item[0]);
});
4
Agus Syahputra

Wenn Ihr System (Chrome/Node.js/Firefox) ES9 unterstützt, verwenden Sie neu die Funktion a_string.matchAll(regex). Wenn Sie ein älteres System haben, finden Sie hier eine Funktion zum einfachen Kopieren und Einfügen

function findAll(regexPattern, sourceString) {
    let output = []
    let match
    // make sure the pattern has the global flag
    let regexPatternWithGlobal = RegExp(regexPattern,"g")
    while (match = regexPatternWithGlobal.exec(sourceString)) {
        // get rid of the string copy
        delete match.input
        // store the match data
        output.Push(match)
    } 
    return output
}

beispielverwendung:

console.log(   findAll(/blah/g,'blah1 blah2')   ) 

ausgänge:

[ [ 'blah', index: 0 ], [ 'blah', index: 6 ] ]
3
Jeff Hykin

Seit ES9 gibt es eine einfachere und bessere Möglichkeit, alle Übereinstimmungen zusammen mit Informationen zu den Erfassungsgruppen und ihrem Index abzurufen:

const string = 'Mice like to dice rice';
const regex = /.ice/gu;
for(const match of string.matchAll(regex)) {
    console.log(match);
}

// ["Mäuse", Index: 0, Eingabe: "Mäuse würfeln gern Reis", Gruppen: undefiniert]

// ["Würfel", Index: 13, Eingabe: "Mäuse würfeln gern Reis", Gruppen: undefiniert]

// ["Reis", Index: 18, Eingabe: "Mäuse würfeln gern Reis", Gruppen: undefiniert]

Es wird derzeit in Chrome, Firefox und Opera unterstützt. Abhängig davon, wann Sie dies gelesen haben, aktivieren Sie diesen Link , um die aktuelle Unterstützung anzuzeigen.

1
iuliu.net

Ich würde definitiv empfehlen, die Funktion String.match () zu verwenden und eine relevante RegEx dafür zu erstellen. Mein Beispiel ist eine Liste von Zeichenfolgen, die häufig beim Durchsuchen von Benutzereingaben nach Stichwörtern und Ausdrücken erforderlich ist.

    // 1) Define keywords
    var keywords = ['Apple', 'orange', 'banana'];

    // 2) Create regex, pass "i" for case-insensitive and "g" for global search
    regex = new RegExp("(" + keywords.join('|') + ")", "ig");
    => /(Apple|orange|banana)/gi

    // 3) Match it against any string to get all matches 
    "Test string for ORANGE's or apples were mentioned".match(regex);
    => ["ORANGE", "Apple"]

Hoffe das hilft!

0

Hier ist ein einzeilige Lösung ohne while-Schleife.

Die Reihenfolge bleibt in der Ergebnisliste erhalten.

Die möglichen Nachteile sind

  1. Es klont den regulären Ausdruck für jedes Spiel.
  2. Das Ergebnis hat eine andere Form als die erwarteten Lösungen. Sie müssen sie noch einmal verarbeiten.
let re = /\s*([^[:]+):\"([^"]+)"/g
let str = '[description:"aoeu" uuid:"123sth"]'

(str.match(re) || []).map(e => RegExp(re.source, re.flags).exec(e))

[ [ 'description:"aoeu"',
    'description',
    'aoeu',
    index: 0,
    input: 'description:"aoeu"',
    groups: undefined ],
  [ ' uuid:"123sth"',
    'uuid',
    '123sth',
    index: 0,
    input: ' uuid:"123sth"',
    groups: undefined ] ]
0
Jae Won Jang

Benutze das...

var all_matches = your_string.match(re);
console.log(all_matches)

Es wird eine Reihe von Übereinstimmungen zurückgeben ... Das würde gut funktionieren ... Aber denken Sie daran, es werden keine Gruppen berücksichtigt. Es werden nur die vollständigen Übereinstimmungen zurückgegeben ...

0
Subham Debnath

Ich vermute, dass, wenn es Randfälle wie zusätzliche oder fehlende Leerzeichen geben würde, dieser Ausdruck mit weniger Grenzen auch eine Option sein könnte:

^\s*\[\s*([^\s\r\n:]+)\s*:\s*"([^"]*)"\s*([^\s\r\n:]+)\s*:\s*"([^"]*)"\s*\]\s*$

Wenn Sie den Ausdruck untersuchen/vereinfachen/ändern möchten, wird er oben rechts in regex101.com erklärt. Wenn Sie möchten, können Sie auch in diesem Link nachsehen, wie es mit einigen Beispieleingaben übereinstimmt.


Prüfung

const regex = /^\s*\[\s*([^\s\r\n:]+)\s*:\s*"([^"]*)"\s*([^\s\r\n:]+)\s*:\s*"([^"]*)"\s*\]\s*$/gm;
const str = `[description:"aoeu" uuid:"123sth"]
[description : "aoeu" uuid: "123sth"]
[ description : "aoeu" uuid: "123sth" ]
 [ description : "aoeu"   uuid : "123sth" ]
 [ description : "aoeu"uuid  : "123sth" ] `;
let m;

while ((m = regex.exec(str)) !== null) {
    // This is necessary to avoid infinite loops with zero-width matches
    if (m.index === regex.lastIndex) {
        regex.lastIndex++;
    }
    
    // The result can be accessed through the `m`-variable.
    m.forEach((match, groupIndex) => {
        console.log(`Found match, group ${groupIndex}: ${match}`);
    });
}

RegEx-Schaltung

jex.im visualisiert reguläre Ausdrücke:

enter image description here

0
Emma

Dies wird bei Ihrem komplexeren Problem nicht wirklich helfen, aber ich poste es trotzdem, da es eine einfache Lösung für Leute ist, die keine globale Suche durchführen, wie Sie es sind.

Ich habe den regulären Ausdruck in der Antwort vereinfacht, um dies zu verdeutlichen (dies ist keine Lösung für Ihr genaues Problem).

var re = /^(.+?):"(.+)"$/
var regExResult = re.exec('description:"aoeu"');
var purifiedResult = purify_regex(regExResult);

// We only want the group matches in the array
function purify_regex(reResult){

  // Removes the Regex specific values and clones the array to prevent mutation
  let purifiedArray = [...reResult];

  // Removes the full match value at position 0
  purifiedArray.shift();

  // Returns a pure array without mutating the original regex result
  return purifiedArray;
}

// purifiedResult= ["description", "aoeu"]

Das sieht ausführlicher aus als es aufgrund der Kommentare ist, so sieht es ohne Kommentare aus

var re = /^(.+?):"(.+)"$/
var regExResult = re.exec('description:"aoeu"');
var purifiedResult = purify_regex(regExResult);

function purify_regex(reResult){
  let purifiedArray = [...reResult];
  purifiedArray.shift();
  return purifiedArray;
}

Beachten Sie, dass alle Gruppen, die nicht übereinstimmen, im Array als undefined -Werte aufgeführt werden.

Bei dieser Lösung wird der ES6-Operator spread verwendet, um das Array von regulären Werten zu bereinigen. Sie müssen Ihren Code durch Babel ausführen, wenn Sie IE11-Unterstützung wünschen.

0
Daniel Tonon