使用string.split()计算Java中字符串的出现次数

使用string.split()计算Java中字符串的出现次数,java,regex,string,Java,Regex,String,我是Java新手。我想我会写一个程序来计算一个句子中一个字符或一系列字符的出现次数。我编写了以下代码。但是我后来看到在ApacheCommons中有一些现成的选项可用 不管怎样,你能看看我的代码并说如果有任何新手的错误吗?我测试了几个案例,效果很好。我可以想到一种情况,如果输入是一个大的文本文件而不是一个小的句子/段落,split()函数可能会出现问题,因为它必须处理一个大变量。不过这是我的猜测,我很想听听你的意见 private static void countCharInString()

我是Java新手。我想我会写一个程序来计算一个句子中一个字符或一系列字符的出现次数。我编写了以下代码。但是我后来看到在ApacheCommons中有一些现成的选项可用

不管怎样,你能看看我的代码并说如果有任何新手的错误吗?我测试了几个案例,效果很好。我可以想到一种情况,如果输入是一个大的文本文件而不是一个小的句子/段落,
split()
函数可能会出现问题,因为它必须处理一个大变量。不过这是我的猜测,我很想听听你的意见

private static void countCharInString() {
    //Get the sentence and the search keyword
    System.out.println("Enter a sentence\n");
    Scanner in = new Scanner(System.in);
    String inputSentence = in.nextLine();
    System.out.println("\nEnter the character to search for\n");
    String checkChar = in.nextLine();
    in.close();

    //Count the number of occurrences
    String[] splitSentence = inputSentence.split(checkChar);
    int countChar = splitSentence.length - 1;
    System.out.println("\nThe character/sequence of characters '" + checkChar + "' appear(s) '" + countChar + "' time(s).");
}

谢谢:)

我能马上想到的一个缺陷是,如果您的
输入语句只包含一次
checkChar
。在这种情况下,
split()

交互示例:

Enter a sentence

onlyme

Enter the character to search for

onlyme

The character/sequence of characters 'onlyme' appear(s) '-1' time(s).
更好的方法是使用
String
.indexOf()
方法来计算出现次数,如下所示:

while ((i = inputSentence.indexOf(checkChar, i)) != -1) {
    count++;
    i = i + checkChar.length();
}
int count = check == null || check.isEmpty() ? 0 : input.replaceAll(".*?(" + check + "|$)", "$1").length() / check.length();

由于边缘情况,
split()
是错误的方法

相反,使用
replaceAll()
删除所有其他字符,然后使用剩余字符的
length()
计算计数:

int count = input.replaceAll(".*?(" + check + "|$)", "$1").length() / check.length();
仅供参考,创建的正则表达式(例如,当
检查='xyz'
时)看起来像
“*?(xyz |$)”
,意思是“直到并包括'xyz'或输入结束的所有内容”,并由捕获的文本替换(如果是输入结束,则为“'xyz”或无内容)。这只留下一个0-n的字符串来复制检查字符串。然后除以支票的长度,得到总数

为了防止检查为null或零长度(导致除以零错误),请编写如下防御代码:

while ((i = inputSentence.indexOf(checkChar, i)) != -1) {
    count++;
    i = i + checkChar.length();
}
int count = check == null || check.isEmpty() ? 0 : input.replaceAll(".*?(" + check + "|$)", "$1").length() / check.length();

split
是一种错误的方法,原因如下:

  • String.split
    接受正则表达式
    • 正则表达式具有具有特殊含义的字符,因此不能将其用于所有字符(不转义)。这需要一个转义函数
    • 性能
      String.split
      针对单个字符进行了优化。如果不是这样的话,您每次都会创建和编译一个正则表达式。不过,
      String.split
      String[]
      创建一个对象,每次调用它时,为其中的每个
      String
      创建一个对象。你对这些东西毫无用处;你只想知道伯爵。尽管未来的广为人知的热点编译器可能能够优化这一点,但当前的编译器却不能——它的速度大约是下面简单计算字符速度的10倍
    • 如果您有重复的
      checkChar
更好的方法要简单得多:只需数一数字符串中与您的
checkChar
匹配的字符。如果你想一想你需要采取什么步骤来计数字符,那就是你自己的结局:

public static int occurrences(String str, char checkChar) {
    int count = 0;
    for (int i = 0, l = str.length(); i < l; i++) {
        if (str.charAt(i) == checkChar)
            count++;
    }
    return count;
}
string.split()


警告:性能计时是大致的数字,取决于许多情况。由于差异是一个数量级,因此可以肯定地说,
String.split
通常较慢。(在jdk 1.8.0-b28 64位上执行的测试,使用了1000万次迭代,在相同的JVM实例中执行了10次测试之后,验证了结果是稳定的,无论是否使用
-Xcomp

侧边注释:不要关闭
系统。
!请注意,您在标题中使用了“character”一词,但在问题和代码中,您实际上是在搜索String@assylias你为什么这么说?如果我删除该行,我会得到“Resource leak:in not closed”@coder\u learner,因为这会关闭控制台输入流,这可能不是一个好主意:在一个更大的程序中,如果您需要在其他地方再次从控制台读取,您将得到一个异常。因此,让控制台保持打开状态可能更好。这不起作用,因为checkChar在代码中是一个
字符串
,所以它可能是多个字符。这个标题有点误导人。@spinlok我错过了。我编辑了我的答案以迎合多个角色。它不再那么漂亮了,但它很管用。