it-swarm.com.de

Anzahl der Übereinstimmungen einer Regex in Javascript zählen

Ich wollte einen Regex schreiben, um die Anzahl der Leerzeichen/Tabs/Zeilenumbrüche in einem Textabschnitt zu zählen. Also schrieb ich naiv folgendes:

numSpaces : function(text) { 
    return text.match(/\s/).length; 
}

Aus unbekannten Gründen gibt es immer 1 zurück. Was ist das Problem mit der obigen Aussage? Ich habe das Problem mit folgendem gelöst: -

numSpaces : function(text) { 
    return (text.split(/\s/).length -1); 
}
76
wai

tl; dr: Generic Pattern Counter

// THIS IS WHAT YOU NEED
const count = (str) => {
  const re = /YOUR_PATTERN_HERE/g
  return ((str || '').match(re) || []).length
}

Für diejenigen, die hierher gekommen sind und nach einer generischen Methode suchen, um die Anzahl der Vorkommen eines Regex-Musters in einer Zeichenfolge zu zählen, und nicht möchten, dass es bei null Vorkommen fehlschlägt, ist dieser Code genau das, was Sie brauchen. Hier ist eine Demonstration:

/*
 *  Example
 */

const count = (str) => {
  const re = /[a-z]{3}/g
  return ((str || '').match(re) || []).length
}

const str1 = 'abc, def, ghi'
const str2 = 'ABC, DEF, GHI'

console.log(`'${str1}' has ${count(str1)} occurrences of pattern '/[a-z]{3}/g'`)
console.log(`'${str2}' has ${count(str2)} occurrences of pattern '/[a-z]{3}/g'`)

Originalantwort

Das Problem mit Ihrem ursprünglichen Code ist, dass Sie die globale Kennung nicht finden:

>>> 'hi there how are you'.match(/\s/g).length;
4

Ohne den g-Teil des Regex passt er nur zum ersten Vorkommen und bleibt dort stehen.

Beachten Sie auch, dass Ihr Regex zweimal hintereinander Leerzeichen zählt:

>>> 'hi  there'.match(/\s/g).length;
2

Wenn dies nicht wünschenswert ist, können Sie Folgendes tun:

>>> 'hi  there'.match(/\s+/g).length;
1
151

Wie in meiner früheren Antwort erwähnt, können Sie RegExp.exec() verwenden, um alle Übereinstimmungen zu durchlaufen und jedes Vorkommen zu zählen. Der Vorteil ist nur auf den Arbeitsspeicher beschränkt, da er insgesamt um 20% langsamer ist als die Verwendung von String.match() .

var re = /\s/g,
count = 0;

while (re.exec(text) !== null) {
    ++count;
}

return count;
9
Ja͢ck

('my string' || []).match(/\s/g).length;

1
Weston Ganger
(('a a a').match(/b/g) || []).length; // 0
(('a a a').match(/a/g) || []).length; // 3

Basierend auf https://stackoverflow.com/a/48195124/16777 , aber behoben, um im Null-Ergebnis-Fall zu funktionieren.

0
Kev

Dies ist sicherlich etwas, das viele Fallen hat. Ich arbeitete mit der Antwort von Paolo Bergantino und erkannte, dass selbst das einige Einschränkungen hat. Die Arbeit mit String-Darstellungen von Datumsangaben war für mich ein guter Ort, um einige der Hauptprobleme schnell zu finden. Beginnen Sie mit einer Eingabezeichenfolge wie folgt: '12-2-2019 5:1:48.670'

und richten Sie die Funktion von Paolo folgendermaßen ein:

function count(re, str) {
    if (typeof re !== "string") {
        return 0;
    }
    re = (re === '.') ? ('\\' + re) : re;
    var cre = new RegExp(re, 'g');
    return ((str || '').match(cre) || []).length;
}

Ich wollte, dass der reguläre Ausdruck übergeben wird, damit die Funktion wiederverwendbar ist. Zweitens wollte ich, dass der Parameter eine Zeichenfolge ist, damit der Client nicht die Regex erstellen muss, sondern einfach auf die Zeichenfolge passt eine standardmäßige String-Dienstprogramm-Klassenmethode.

Hier sehen Sie, dass ich mich mit der Eingabe beschäftige. Mit den folgenden:

if (typeof re !== "string") {
    return 0;
}

Ich stelle sicher, dass die Eingabe nicht mit dem Literal 0, false, undefined oder null übereinstimmt, von denen keine Zeichenfolgen sind. Da diese Literale nicht in der Eingabezeichenfolge enthalten sind, sollten keine Übereinstimmungen vorhanden sein, jedoch sollte '0' als Zeichenfolge angegeben werden.

Mit den folgenden:

re = (re === '.') ? ('\\' + re) : re;

Ich habe es mit der Tatsache zu tun, dass der RegExp-Konstruktor (ich denke, falsch) den String '.' als All-Character-Matcher \.\ interpretiert.

Da ich den RegExp-Konstruktor verwende, muss ich ihm schließlich das globale 'g'-Flag zuweisen, damit alle Übereinstimmungen gezählt werden, nicht nur die ersten, ähnlich den Vorschlägen in anderen Beiträgen.

Mir ist klar, dass dies eine sehr späte Antwort ist, aber es könnte hilfreich sein, dass jemand hier stolpert. Übrigens hier ist die TypeScript-Version:

function count(re: string, str: string): number {
    if (typeof re !== 'string') {
        return 0;
    }
    re = (re === '.') ? ('\\' + re) : re;
    const cre = new RegExp(re, 'g');    
    return ((str || '').match(cre) || []).length;
}
0
Michael Coxon