Policz liczbę dopasowań wyrażenia regularnego w JavaScript


Chciałem napisać wyrażenie regularne, aby policzyć liczbę spacji/tabulatorów/nowej linii w fragmencie tekstu. Więc naiwnie napisałem: -
numSpaces : function(text) { 
return text.match(/\s/).length;
}

Z jakiegoś nieznanego powodu zawsze zwraca
1
. Jaki jest problem z powyższym stwierdzeniem? Od tego czasu rozwiązałem ten problem w następujący sposób: -
numSpaces : function(text) { 
return (text.split(/\s/).length -1);
}

Zaproszony:
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:


tl; dr: ogólny licznik wzorców

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

Dla tych, którzy przybyli tutaj i szukają ogólnego sposobu zliczania liczby wystąpień wzorca wyrażenia regularnego w ciągu znaków i nie chcą, aby to się nie powiodło, jeśli wystąpi zero, ten kod jest tym, czego potrzebujesz. Oto demo:
<div class="snippet-code">
<div class="snippet" data-babel="false" data-console="true" data-hide="false" data-lang="js">
<pre class="snippet-code-js lang-js prettyprint-override">
/*
* 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'`)


oryginalna odpowiedź

Problem z oryginalnym kodem polega na tym, że go brakuje

identyfikator globalny
http://www.javascriptkit.com/jsref/regexp.shtml
:
>>> 'hi there how are you'.match(/\s/g).length;
4

Bez części
g
wyrażenia regularnego dopasuje tylko pierwsze wystąpienie i na tym zakończy.
Pamiętaj również, że Twoje wyrażenie regularne będzie liczyć dwa razy następujące po sobie spacje:
>>> 'hi there'.match(/\s/g).length;
2

Jeśli nie jest to pożądane, możesz to zrobić:
>>> 'hi there'.match(/\s+/g).length;
1
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Jak wspomniano w

moja poprzednia odpowiedź
https://stackoverflow.com/a/23385429/1338292, możesz użyć
RegExp.exec()
https://developer.mozilla.org/ ... /exec
iterować po wszystkich dopasowaniach i liczyć każde wystąpienie; Zaleta jest ograniczona tylko pamięcią, ponieważ ogólnie jest około 20% wolniejsza niż użycie
String.match()
https://developer.mozilla.org/ ... match
.
var re =/\s/g,
count = 0;while (re.exec(text) !== null) {
++count;
}return count;
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

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

Oparte na

https://stackoverflow.com/a/48195124/16777
https://stackoverflow.com/a/48195124/16777
ale ustalone dla prawdziwej pracy w przypadku zerowych wyników.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

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

Anonimowy użytkownik

Potwierdzenie od:

Jest to z pewnością coś, co ma wiele pułapek. Pracowałem z odpowiedzią Paolo Bergantino i zdałem sobie sprawę, że nawet to ma pewne ograniczenia. Zauważyłem, że praca z reprezentacjami dat w postaci ciągów znaków jest dobrym miejscem do szybkiego znalezienia niektórych podstawowych problemów. Zacznij od następującego wiersza wprowadzania:
'12 -2-2019 5: 1: 48.670 '
i skonfiguruj funkcję Paolo w następujący sposób:
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;
}

Chciałem, aby wyrażenie regularne zostało przekazane, aby funkcja była bardziej przydatna do ponownego użycia, po drugie, chciałem, aby parametr był ciągiem, aby klient nie musiał wykonywać wyrażenia regularnego, ale po prostu dopasował ciąg, jak standardowa metoda narzędzia do ciągów klasa.
Teraz tutaj widać, że mam do czynienia z problemami z danymi wejściowymi. Korzystając z następujących środków:
if (typeof re !== "string") {
return 0;
}

Gwarantuję, że dane wejściowe nie mają nic wspólnego z literałami
0
,
false
,
undefined
lub
null
, żaden z który nie jest ciągiem. Ponieważ te literały nie są częścią ciągu wejściowego, nie powinno być żadnych dopasowań, ale muszą one pasować do
„0”
, który jest ciągiem.
Korzystając z następujących środków:
re = (re === '.') ? ('\\' + re) : re;

Mam do czynienia z faktem, że konstruktor RegExp (myślę źle) zinterpretuje wiersz
'.'
jako All character matcher
\. \
Wreszcie, ponieważ używam konstruktora RegExp, muszę nadać mu globalną flagę
'g'
, aby uwzględniał wszystkie dopasowania, a nie tylko pierwsze, jak sugestie w innych postach.
Zdaję sobie sprawę, że to bardzo późna odpowiedź, ale może być pomocna dla kogoś, kto się tu potyka. BTW tutaj jest wersja TypeScript:
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;
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

co powiesz na to
function isint(str){
if(str.match(/\d/g).length==str.length){
return true;
}
else {
return false
}
}

Aby odpowiedzieć na pytania, Zaloguj się lub Zarejestruj się