जावास्क्रिप्ट में एक रेगेक्स के मैचों की संख्या


98

मैं पाठ के एक हिस्से में रिक्त स्थान / टैब / न्यूलाइन की संख्या की गणना करने के लिए एक रेगेक्स लिखना चाहता था। इसलिए मैंने भोलेपन से निम्नलिखित लिखा: -

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

कुछ अज्ञात कारणों से यह हमेशा लौटता है 1। उपरोक्त कथन से क्या समस्या है? मैंने निम्नलिखित के साथ समस्या को हल किया है: -

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

जवाबों:


191

tl; dr: जेनेरिक पैटर्न काउंटर

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

उन लोगों के लिए जो एक स्ट्रिंग में रेगेक्स पैटर्न की घटनाओं की संख्या की गणना करने के लिए एक सामान्य तरीके की तलाश में थे, और शून्य घटनाओं होने पर इसे विफल नहीं करना चाहते, यह कोड वह है जो आपको चाहिए। यहाँ एक प्रदर्शन है:

/*
 *  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'`)

मूल उत्तर

आपके प्रारंभिक कोड के साथ समस्या यह है कि आप वैश्विक पहचानकर्ता को याद कर रहे हैं :

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

gरेगेक्स के भाग के बिना यह केवल पहली घटना से मेल खाएगा और वहां रुक जाएगा।

यह भी ध्यान दें कि आपका रेगेक्स लगातार दो बार गिनती करेगा:

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

यदि वह वांछनीय नहीं है, तो आप ऐसा कर सकते हैं:

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

5
यह तब तक काम करता है जब तक आपके इनपुट में कम से कम एक स्थान हो। अन्यथा, मैच () कष्टप्रद रूप से अशक्त हो जाता है।
sfink

3
sfink सही है, आप निश्चित रूप से जांचना चाहते हैं कि क्या मैच () शून्य हुआ:var result = text.match(/\s/g); return result ? result.length : 0;
ग्रास डबल

37
: आप भी इस निर्माण का उपयोग करके अशक्त के खिलाफ की रक्षा कर सकते हैं( str.match(...) || [] ).length
a'r

11

जैसा कि मेरे पहले उत्तर में उल्लेख किया गया है , आप RegExp.exec()सभी मैचों पर पुनरावृति करने और प्रत्येक घटना को गिनने के लिए उपयोग कर सकते हैं ; लाभ केवल मेमोरी तक सीमित है, क्योंकि पूरे पर यह उपयोग करने की तुलना में लगभग 20% धीमा है String.match()

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

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

return count;

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

Https://stackoverflow.com/a/48195124/16777 के आधार पर लेकिन वास्तव में शून्य-परिणाम के मामले में काम करने के लिए तय किया गया।



0

यह निश्चित रूप से कुछ ऐसा है जिसमें बहुत सारे जाल हैं। मैं पाओलो बेरेगिनो के जवाब के साथ काम कर रहा था, और यह महसूस कर रहा था कि इसकी कुछ सीमाएँ भी हैं। मैंने पाया कि तारीखों के स्ट्रिंग निरूपण के साथ काम करने से कुछ मुख्य समस्याओं का जल्द पता चल जाता है। इस तरह एक इनपुट स्ट्रिंग के साथ शुरू करें: '12-2-2019 5:1:48.670'

और पाओलो के कार्य को इस तरह स्थापित किया:

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

मैं चाहता था कि नियमित अभिव्यक्ति को पारित किया जाए, ताकि फ़ंक्शन अधिक पुन: प्रयोज्य हो, दूसरी बात, मैं चाहता था कि पैरामीटर एक स्ट्रिंग हो, ताकि क्लाइंट को रेगेक्स बनाने की ज़रूरत न हो, लेकिन बस स्ट्रिंग पर मेल खाए, जैसे एक मानक स्ट्रिंग उपयोगिता वर्ग विधि।

अब, यहां आप देख सकते हैं कि मैं इनपुट के साथ समस्याओं से निपट रहा हूं। निम्नलिखित के साथ:

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

मुझे लगता है कि इनपुट शाब्दिक ऐसा कुछ नहीं है यह सुनिश्चित कर रहा हूँ 0, false, undefined, या null, में से कोई भी जो तार कर रहे हैं। चूंकि ये शाब्दिक इनपुट स्ट्रिंग में नहीं हैं, इसलिए कोई मिलान नहीं होना चाहिए, लेकिन यह मेल खाना चाहिए '0', जो एक स्ट्रिंग है।

निम्नलिखित के साथ:

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

मैं इस तथ्य से निपट रहा हूं कि RegExp कंस्ट्रक्टर (मुझे लगता है, गलत तरीके से) स्ट्रिंग की व्याख्या '.'सभी चरित्र मिलानकर्ता के रूप में करेगा\.\

अंत में, क्योंकि मैं RegExp कंस्ट्रक्टर का उपयोग कर रहा हूं, इसलिए मुझे इसे वैश्विक 'g'ध्वज देने की आवश्यकता है, ताकि यह अन्य पदों के सुझावों के समान, केवल पहले एक ही नहीं, बल्कि सभी मैचों को गिना जाए।

मुझे एहसास है कि यह एक बहुत देर से जवाब है, लेकिन यह यहाँ साथ ठोकर खाने वाले किसी के लिए उपयोगी हो सकता है। BTW यहाँ टाइपस्क्रिप्ट संस्करण है:

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.