【问题标题】:Count number of matches of a regex in Javascript计算 Javascript 中正则表达式的匹配数
【发布时间】:2009-07-02 06:15:52
【问题描述】:

我想编写一个正则表达式来计算一段文本中空格/制表符/换行符的数量。于是我天真地写了以下内容:-

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

由于某些未知原因,它总是返回1。上述说法有什么问题?我已经解决了以下问题:-

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

【问题讨论】:

    标签: javascript regex


    【解决方案1】:

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

    原答案

    您的初始代码的问题是您缺少global identifier

    >>> '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
    

    【讨论】:

    • 只要您的输入中至少有一个空格,它就可以工作。否则,match() 会烦人地返回 null。
    • sfink 是对的,你肯定要检查 match() 是否返回 null:var result = text.match(/\s/g); return result ? result.length : 0;
    • 您还可以使用以下构造来防止出现空值:( str.match(...) || [] ).length
    • ('string'.match(/\s/g) || []).length 有什么问题?
    • @JoãoPimentelFerreira 不同之处在于:如果str 为空,则str.match() 将失败,但(str || '').match() 不会。
    【解决方案2】:

    my earlier answer 中所述,您可以使用RegExp.exec() 遍历所有匹配项并计算每次出现的次数;优势仅限于内存,因为总的来说它比使用 String.match() 慢 20%。

    var re = /\s/g,
    count = 0;
    
    while (re.exec(text) !== null) {
        ++count;
    }
    
    return count;
    

    【讨论】:

      【解决方案3】:
      (('a a a').match(/b/g) || []).length; // 0
      (('a a a').match(/a/g) || []).length; // 3
      

      基于https://stackoverflow.com/a/48195124/16777,但固定为在零结果情况下实际工作。

      【讨论】:

        【解决方案4】:

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

        【讨论】:

        • 我觉得你把|| []放错地方了,应该是('my string'.match(/\s/g) || []).length
        【解决方案5】:

        这是与@Paolo Bergantino 的答案类似的解决方案,但使用了现代运营商。我会在下面解释。

            const matchCount = (str, re) => {
              return str?.match(re)?.length ?? 0;
            };
        
            // usage
            
            let numSpaces = matchCount(undefined, /\s/g);
            console.log(numSpaces); // 0
            numSpaces = matchCount("foobarbaz", /\s/g);
            console.log(numSpaces); // 0
            numSpaces = matchCount("foo bar baz", /\s/g);
            console.log(numSpaces); // 2
        

        ?.optional chaining operator。它允许您尽可能多地链接调用,而不必担心在此过程中是否存在未定义/空值。将str?.match(re) 视为

        if (str !== undefined && str !== null) {
            return str.match(re);
        } else {
            return undefined;
        }
        

        这与@Paolo Bergantino 的略有不同。他们的写法是这样的:(str || '')。这意味着如果strfalsy,则返回''。 0 是假的。 document.all 是假的。在我看来,如果有人将它们作为字符串传递给这个函数,那可能是因为程序员错误。因此,我宁愿被告知我正在做一些不明智的事情,也不愿解决为什么我的长度一直为 0。

        ??nullish coalescing operator。将其视为||,但更具体。如果|| 的左侧计算结果为falsy,它会执行右侧。但?? 仅在左侧未定义或为空时执行。

        请记住,?.length ?? 0 中的无效合并运算符将返回与使用 ?.length || 0 相同的内容。不同之处在于,如果length 返回 0,则不会执行右侧...但是无论您使用|| 还是??,结果都将为0。

        老实说,在这种情况下,我可能会将其更改为 ||,因为更多的 JavaScript 开发人员熟悉该运算符。也许有人可以告诉我??|| 在这种情况下的好处,如果有的话。

        最后,我更改了签名,因此该函数可以用于任何正则表达式。

        哦,这是一个打字稿版本:

            const matchCount = (str: string, re: RegExp) => {
              return str?.match(re)?.length ?? 0;
            };
        

        【讨论】:

          【解决方案6】:

          这肯定是有很多陷阱的东西。我正在使用 Paolo Bergantino 的答案,并意识到即使这样也有一些局限性。我发现使用日期的字符串表示是快速找到一些主要问题的好地方。从这样的输入字符串开始: '12-2-2019 5:1:48.670'

          并像这样设置 Paolo 的函数:

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

          我确保输入不是文字 0falseundefinednull,它们都不是字符串。由于这些文字不在输入字符串中,所以应该没有匹配项,但应该匹配'0',这是一个字符串。

          以下内容:

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

          我正在处理 RegExp 构造函数将(我认为错误地)将字符串 '.' 解释为全字符匹配器 \.\ 的事实

          最后,因为我使用的是 RegExp 构造函数,我需要给它一个全局 'g' 标志,以便它计算所有匹配项,而不仅仅是第一个匹配项,类似于其他帖子中的建议。

          我意识到这是一个非常晚的答案,但它可能对在这里磕磕绊绊的人有所帮助。顺便说一句,这是 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;
          }
          

          【讨论】:

            【解决方案7】:

            使用现代语法避免了创建一个虚拟数组来计算长度为 0 的需要

            const countMatches = (exp, str) => str.match(exp)?.length ?? 0;
            

            必须将exp 作为RegExpstr 作为String 传递。

            【讨论】:

              【解决方案8】:

              这样怎么样

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2011-11-14
                • 1970-01-01
                • 2011-11-29
                • 2012-09-22
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多