【问题标题】:Count number of commas within a string except for commas between double quotes计算字符串中逗号的数量,双引号之间的逗号除外
【发布时间】:2012-04-11 19:32:05
【问题描述】:

我有以下函数来计算字符串中逗号(或任何其他字符)的数量,而不计算双引号内的逗号。我想知道是否有更好的方法来实现这一点,或者即使你能找到这个函数可能崩溃的情况。

public int countCharOfString(char c, String s) {
    int numberOfC = 0;
    boolean doubleQuotesFound = false;
    for(int i = 0; i < s.length(); i++){
        if(s.charAt(i) == c && !doubleQuotesFound){
            numberOfC++;
        }else if(s.charAt(i) == c && doubleQuotesFound){
            continue;
        }else if(s.charAt(i) == '\"'){
            doubleQuotesFound = !doubleQuotesFound;
        }
    }
    return numberOfC;
}

感谢您的建议

【问题讨论】:

  • 用 switch 语句替换你的 if / else 东西。

标签: java string performance counter


【解决方案1】:

这个实现有两个不同:

  • 使用CharSequence 代替字符串
  • 不需要boolean 值来跟踪我们是否在带引号的子序列中。

功能:

public static int countCharOfString(char quote, CharSequence sequence) {

    int total = 0, length = sequence.length();

    for(int i = 0; i < length; i++){
        char c = sequence.charAt(i);
        if (c == '"') {
            // Skip quoted sequence
            for (i++; i < length && sequence.charAt(i)!='"'; i++) {}
        } else if (c == quote) {
            total++;
        }
    }

    return total;
 }

【讨论】:

    【解决方案2】:
    public static int countCharOfString(char c, String s)
    {
        int numberOfC = 0;
        int innerC = 0;
        boolean holdDoubleQuotes = false;
        for(int i = 0; i < s.length(); i++)
        {
            char r = s.charAt(i);
            if(i == s.length() - 1 && r != '\"')
            {
                numberOfC += innerC;
                if(r == c) numberOfC++;
            }
            else if(r == c && !holdDoubleQuotes) numberOfC++;
            else if(r == c && holdDoubleQuotes) innerC++;
            else if(r == '\"' && holdDoubleQuotes)
            {
                holdDoubleQuotes = false;
                innerC = 0;
            }
            else if(r == '\"' && !holdDoubleQuotes) holdDoubleQuotes = true;
        }
        return numberOfC;
    }
    

    System.out.println(countCharOfString(',', "Hello, BRabbit27, how\",,,\" are, you?"));
    

    输出:

    3
    

    另一种方法是使用正则表达式:

    public static int countCharOfString(char c, String s)
    {
       s = " " + s + " "; // To make the first and last commas to be counted
       return s.split("[^\"" + c + "*\"][" + c + "]").length - 1;
    }
    

    【讨论】:

    • 我手边没有 Java 编译器处理程序,但如果引号中有多个逗号,这看起来会失败。有 if(r == c && !holdDoubleQuotes) numberOfC++; 会更好吗?并删除 numberOfC-- 稍后?
    【解决方案3】:
    • 您不应在循环内多次调用charAt()。使用 char 变量。
    • 您不应该为每次迭代调用length()。在循环之前使用int
    • 您应该避免与 c 重复比较 - 使用嵌套 if/else。

    【讨论】:

      【解决方案4】:

      也许不是最快的......

      public int countCharOfString(char c, String s) {
          final String removedQuoted = s.replaceAll("\".*?\"", "");
          int total = 0;
          for(int i = 0; i < removedQuoted.length(); ++i)
              if(removedQuoted.charAt(i) == c)
                  ++total;
          return total;
      }
      

      【讨论】:

      • 其实我分析了它,它更耗时。感谢您的帮助!
      • @BRabbit27:好吧,因为它涉及正则表达式,它可能是这里最慢的解决方案 - 但也是最短的解决方案之一:-)
      【解决方案5】:

      更简单,更不容易出错(是的,性能不如逐个字符地遍历字符串并手动跟踪所有内容):

      public static int countCharOfString(char c, String s) {
        s = s.replaceAll("\".*?\"", "");
        int cnt = 0;
        for (int foundAt = s.indexOf(c); foundAt > -1; foundAt = s.indexOf(c, foundAt+1)) 
          cnt++;
        return cnt;
      }
      

      【讨论】:

        【解决方案6】:

        需要很大的字符串才能产生很大的不同。

        此代码更快的原因是它平均每个循环包含 1.5 个检查,而不是每个循环 3 个检查。它通过使用两个循环来做到这一点,一个用于引用状态,一个用于未引用状态。

        public static void main(String... args) {
            String s = generateString(20 * 1024 * 1024);
            for (int i = 0; i < 15; i++) {
                long start = System.nanoTime();
                countCharOfString(',', s);
                long mid = System.nanoTime();
                countCharOfString2(',', s);
                long end = System.nanoTime();
                System.out.printf("countCharOfString() took %.3f ms, countCharOfString2() took %.3f ms%n",
                        (mid - start) / 1e6, (end - mid) / 1e6);
            }
        }
        
        private static String generateString(int length) {
            StringBuilder sb = new StringBuilder(length);
            Random rand = new Random(1);
            while (sb.length() < length)
                sb.append((char) (rand.nextInt(96) + 32)); // includes , and "
            return sb.toString();
        }
        
        public static int countCharOfString2(char c, String s) {
            int numberOfC = 0, i = 0;
            while (i < s.length()) {
                // not quoted
                while (i < s.length()) {
                    char ch = s.charAt(i++);
                    if (ch == c)
                        numberOfC++;
                    else if (ch == '"')
                        break;
                }
                // quoted
                while (i < s.length()) {
                    char ch = s.charAt(i++);
                    if (ch == '"')
                        break;
                }
            }
            return numberOfC;
        }
        
        
        public static int countCharOfString(char c, String s) {
            int numberOfC = 0;
            boolean doubleQuotesFound = false;
            for (int i = 0; i < s.length(); i++) {
                if (s.charAt(i) == c && !doubleQuotesFound) {
                    numberOfC++;
                } else if (s.charAt(i) == c && doubleQuotesFound) {
                    continue;
                } else if (s.charAt(i) == '\"') {
                    doubleQuotesFound = !doubleQuotesFound;
                }
            }
            return numberOfC;
        }
        

        打印

        countCharOfString() took 33.348 ms, countCharOfString2() took 31.381 ms
        countCharOfString() took 28.265 ms, countCharOfString2() took 25.801 ms
        countCharOfString() took 28.142 ms, countCharOfString2() took 14.576 ms
        countCharOfString() took 28.372 ms, countCharOfString2() took 14.540 ms
        countCharOfString() took 28.191 ms, countCharOfString2() took 14.616 ms
        

        【讨论】:

          【解决方案7】:

          你也可以使用正则表达式和 String.split()

          它可能看起来像这样:

          public int countNonQuotedOccurrences(String inputstring, char searchChar)
          {
            String regexPattern = "[^\"]" + searchChar + "[^\"]";
            return inputString.split(regexPattern).length - 1;
          }
          

          免责声明:

          这只是展示了基本的方法。

          上面的代码不会在字符串的开头或结尾检查searchChar。

          您可以手动检查或添加到 regexPattern。

          【讨论】:

          • 我不喜欢 split 的地方是,如果字符串以 char c 结尾,则它们不会被计算在内。例如Hi,How,Are,You,,, 将返回 3 而不是 6。
          • 感谢您的宝贵时间和帮助!
          • 刚要添加...当字符位于字符串的开头或结尾时,上面的代码将不起作用。您可以单独测试或添加一些“或”正则表达式。
          • String.split 使用正则表达式。并且正则表达式 - 对于这样简单的字符串操作 - 非常昂贵。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-10-31
          • 2016-01-18
          • 2015-08-05
          • 2011-12-25
          • 2020-04-05
          相关资源
          最近更新 更多