Zählen Sie die Anzahl der Übereinstimmungen eines regulären Ausdrucks in Javascript

98

Ich wollte einen regulären Ausdruck schreiben, um die Anzahl der Leerzeichen / Tabulatoren / Zeilenumbrüche in einem Textblock zu zählen. Also schrieb ich naiv folgendes: -

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

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

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

Antworten:

190

tl; dr: Generischer Musterzähler

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

Für diejenigen, die hier angekommen 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 fehlschlägt, wenn es keine Vorkommen gibt, 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'`)

Ursprüngliche Antwort

Das Problem mit Ihrem ursprünglichen Code ist, dass Ihnen die globale Kennung fehlt :

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

Ohne den gTeil des regulären Ausdrucks stimmt er nur mit dem ersten Vorkommen überein und stoppt dort.

Beachten Sie auch, dass Ihre Regex aufeinanderfolgende Leerzeichen zweimal 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
Paolo Bergantino
quelle
5
Dies funktioniert, solange Sie mindestens ein Leerzeichen in Ihrer Eingabe haben. Andernfalls gibt match () ärgerlicherweise null zurück.
Sfink
3
sfink ist richtig, Sie möchten auf jeden Fall überprüfen, ob match () null zurückgegeben hat:var result = text.match(/\s/g); return result ? result.length : 0;
Gras Double
37
: Sie können auch mit Hilfe dieser Konstruktion gegen die Null schützen( str.match(...) || [] ).length
a'r
11

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

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

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

return count;
Jack
quelle
2

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

Weston Ganger
quelle
1
Ich denke, Sie setzen das || []an die falsche Stelle, es sollte sein('my string'.match(/\s/g) || []).length
woojoo666
0

Dies ist sicherlich etwas, das viele Fallen hat. Ich habe mit Paolo Bergantinos Antwort gearbeitet und festgestellt, dass selbst das einige Einschränkungen hat. Ich fand die Arbeit mit Zeichenfolgendarstellungen von Daten ein guter Ort, um schnell einige der Hauptprobleme 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 wiederverwendbarer ist. Zweitens wollte ich, dass der Parameter eine Zeichenfolge ist, damit der Client den regulären Ausdruck nicht erstellen muss, sondern einfach mit der Zeichenfolge übereinstimmt eine Standard-String-Utility-Klassenmethode.

Hier können Sie sehen, dass ich Probleme mit der Eingabe habe. Mit den folgenden:

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

Ich bin sicher , dass die Eingabe nicht so etwas wie die wörtlichen 0, false, undefined, oder null, von denen keine Strings sind. Da diese Literale nicht in der Eingabezeichenfolge enthalten sind, sollte es keine Übereinstimmungen geben, aber es sollte übereinstimmen '0', was eine Zeichenfolge ist.

Mit den folgenden:

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

Ich habe es damit zu tun, dass der RegExp-Konstruktor (ich denke falsch) die Zeichenfolge '.'als All-Character-Matcher interpretiert\.\

Da ich den RegExp-Konstruktor verwende, muss ich ihm das globale 'g'Flag geben, damit alle Übereinstimmungen gezählt werden, nicht nur die erste, ähnlich wie in den Vorschlägen in anderen Posts.

Mir ist klar, dass dies eine extrem späte Antwort ist, aber es könnte hilfreich sein, wenn jemand hier entlang stolpert. Übrigens ist hier 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;
}
Michael Coxon
quelle
-2

wie wäre es so

function isint(str){
    if(str.match(/\d/g).length==str.length){
        return true;
    }
    else {
         return false
    }
}
anders
quelle