为什么以下算法对我来说不停止?
(str是我要搜索的字符串,findStr是我要寻找的字符串)

String str = "helloslkhellodjladfjhello";
String findStr = "hello";
int lastIndex = 0;
int count = 0;

while (lastIndex != -1) {
    lastIndex = str.indexOf(findStr,lastIndex);

    if( lastIndex != -1)
        count++;

    lastIndex += findStr.length();
}

System.out.println(count);


评论

我们在Udacity中做的非常好:我们使用了newSTR = str.replace(findStr,“”);并返回count =((str.length()-newSTR.length())/ findStr.length());

字符的类似问题:stackoverflow.com/q/275944/873282

您是否也不想考虑搜索字符串的前缀为其后缀的情况?在那种情况下,我认为任何建议的答案都行不通。这是一个例子。在那种情况下,您将需要更复杂的算法,例如在CLRS本书中编码的Knuth Morris Pratt(KMP)

它对您而言并不暂停,因为在达到“暂停”条件(lastIndex == -1)后,您可以通过增加lastIndex(lastIndex + = findStr.length();)的值来重置它。

#1 楼

最后一行造成了问题。 lastIndex永远不会为-1,因此将存在无限循环。可以通过将代码的最后一行移到if块中来解决此问题。

String str = "helloslkhellodjladfjhello";
String findStr = "hello";
int lastIndex = 0;
int count = 0;

while(lastIndex != -1){

    lastIndex = str.indexOf(findStr,lastIndex);

    if(lastIndex != -1){
        count ++;
        lastIndex += findStr.length();
    }
}
System.out.println(count);


评论


此回复是我一个小时前发表的帖子的完整副本;)

–奥利维尔
09年4月20日在14:16

请注意,这可能会或可能不会返回预期的结果。使用子字符串“ aa”和搜索“ aaa”的字符串,预期的出现次数可能是一个(此代码返回),但也可能是两个(在这种情况下,您将需要“ lastIndex ++”而不是“ lastIndex + =” findStr.length()“)取决于您要查找的内容。

–斯坦尼斯拉夫·克尼亚泽夫(Stanislav Kniazev)
09年4月23日在12:52

@olivier没有看到... :( @ @stan绝对正确...我只是在解决问题中的代码...猜测它取决于bobcom在字符串中出现的次数是什么意思...

– codebreach
09年4月24日在20:52

人们什么时候会学习将这种东西包装在静态复制和粘贴方法中?请参阅下面的答案,它也经过了优化。

–mmm
2015年4月12日9:54



这里的道理是,如果您打算写一个答案,请先检查是否有人已经写出了完全相同的答案。相同的答案出现两次实际上没有任何好处,无论您的答案是复制还是单独撰写。

–达伍德·伊本·卡里姆(Dawood ibn Kareem)
18年7月11日在4:03

#2 楼

如何使用来自Apache Commons Lang的StringUtils.countMatches?

String str = "helloslkhellodjladfjhello";
String findStr = "hello";

System.out.println(StringUtils.countMatches(str, findStr));


输出:

3


评论


不管这个建议多么正确,由于它没有回答OP的问题,因此不能被接受为解决方案

–kommradHomer
14年7月12日在11:36

是不推荐使用的东西还是..我的IDE无法识别

–Vamsi Pavan Mahesh
14年7月18日在16:30

@VamsiPavanMahesh StringUtils是Apache Commons的一个库。检查这里:commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/…

– Anup
2015年9月15日上午11:33

该答案是彼得·劳瑞(Peter Lawrey)一天前的答案的副本(请参阅下文)。

–区
16 Mar 14 '14 at 14:36

StringUtils还没有countMatches方法。

–格子衬衫
18年5月10日在9:19

#3 楼

您的lastIndex += findStr.length();放在方括号之外,导致无限循环(当未发现任何情况时,lastIndex始终为findStr.length())。

这是固定版本:

String str = "helloslkhellodjladfjhello";
String findStr = "hello";
int lastIndex = 0;
int count = 0;

while (lastIndex != -1) {

    lastIndex = str.indexOf(findStr, lastIndex);

    if (lastIndex != -1) {
        count++;
        lastIndex += findStr.length();
    }
}
System.out.println(count);


#4 楼

较短的版本。 ;)

String str = "helloslkhellodjladfjhello";
String findStr = "hello";
System.out.println(str.split(findStr, -1).length-1);


评论


返回haystack.split(Pattern.quote(needle),-1).length-1;如果例如needle =“ :)”

– Mr_and_Mrs_D
2012年12月16日16:01

@lOranger如果不使用,-1,它将删除结尾的匹配项。

– Peter Lawrey
2012-12-28 12:02

太好了,谢谢!这将教我阅读javadoc中的小行...

– LaurentGrégoire
2012年12月28日在12:05

真好!但这只包括不重叠的比赛,不是吗?例如。匹配“ aaa”中的“ aa”将返回1,而不是2?当然,包括重叠或不重叠的匹配都是有效的,并且取决于用户要求(也许一个标志来指示计数重叠,是/否)?

–Cornel Masson
13年4月26日在9:24



-1 ..尝试在“ aaaa”和“ aa”上运行它。正确的答案是3而不是2。

– Kalyanaraman Santhanam
2014年9月15日下午6:06

#5 楼

您真的必须自己处理匹配吗?特别是如果您只需要出现次数,则正则表达式会更整洁:

String str = "helloslkhellodjladfjhello";
Pattern p = Pattern.compile("hello");
Matcher m = p.matcher(str);
int count = 0;
while (m.find()){
    count +=1;
}
System.out.println(count);     


评论


这找不到特殊字符,下面的字符串将找到0:String str =“ hel + loslkhel + lodjladfjhel + lo”;模式p = Pattern.compile(“ hel + lo”);

–本
2014年2月2日在4:09



是的,如果您正确表达您的正则表达式会。尝试使用Pattern.compile(“ hel \\ + lo”); +号在正则表达式中有特殊含义,需要转义。

–吉恩
2014年2月2日,9:42

如果您要获取任意String并将其用作与所有特殊正则表达式字符完全忽略的完全匹配的字符串,Pattern.quote(str)是您的朋友!

– Mike Furtak
2015年1月10日18:11



当str =“ aaaaaa”时,这不适用于“ aaa”。有4个答案,但您给2个

– Pujan
16-10-29在12:02

此解决方案不适用于这种情况:str =“这是一个测试\\ n \\ r字符串”,subStr =“ \\ r”,它显示0次。

–马克西姆·奥夫亚尼科夫(Maksym Ovsianikov)
17年12月1日在23:21

#6 楼

我很惊讶没有人提到这一支班轮。它简单,简洁,并且性能比str.split(target, -1).length-1

public static int count(String str, String target) {
    return (str.length() - str.replace(target, "").length()) / target.length();
}


评论


应该是最佳答案。谢谢!

–lakam99
19年11月21日在1:55

完美的答案!

–克里希纳
10月1日7:07

仅供参考:由于目标字符串为空时除以零,因此将引发ArithmeticException。

–阿提拉
10月16日8:40

#7 楼

在这里,用一种不错的可重用的方法包装了它:

public static int count(String text, String find) {
        int index = 0, count = 0, length = find.length();
        while( (index = text.indexOf(find, index)) != -1 ) {                
                index += length; count++;
        }
        return count;
}


#8 楼

String str = "helloslkhellodjladfjhello";
String findStr = "hello";
int lastIndex = 0;
int count = 0;

while((lastIndex = str.indexOf(findStr, lastIndex)) != -1) {
     count++;
     lastIndex += findStr.length() - 1;
}
System.out.println(count);
循环末尾的

为3;希望对您有帮助

评论


该代码包含错误。如果我们搜索单个字符,则findStr.length()-1返回0,并且我们处于无休止的循环中。

– Jan Bodnar
2014-09-26 10:58

#9 楼

public int countOfOccurrences(String str, String subStr) {
  return (str.length() - str.replaceAll(Pattern.quote(subStr), "").length()) / subStr.length();
}


评论


好答案。您介意添加一些有关其工作原理的注释吗?

–santhosh kumar
17-09-27在20:07

当然,str-是我们的源字符串,subStr-是一个子字符串。目的是计算str中subStr的出现量。为此,我们使用公式:(ab)/ c,其中a-str的长度,b-没有所有subStr出现的str的长度(为此,我们从str中删除了subStr的所有出现),c-subStr的长度。因此,基本上,我们从str的长度中提取出-没有所有subStr的str的长度,然后将结果除以subStr的长度。如果您还有其他疑问,请告诉我。

–马克西姆·奥夫亚尼科夫(Maksym Ovsianikov)
17-10-17在0:35

Santhosh,欢迎您!重要的部分是对SubStr使用Pattern.quote,否则在某些情况下可能会失败,例如:str =“这是一个测试\\ n \\ r字符串”,subStr =“ \\ r”。此处提供的一些类似答案未使用模式,因此在这种情况下它们将失败。

–马克西姆·奥夫亚尼科夫(Maksym Ovsianikov)
17年12月1日23:17



没有理由使用正则表达式,请使用replace,而不是replaceAll。

– NateS
5月13日13:14

#10 楼

许多给定的答案都因以下一项或多项而失败:


任意长度的模式
重叠匹配(例如计数“ 23232”或“ aa”中的“ 232”在“ aaa”中)
正则表达式元字符

这是我写的内容:

static int countMatches(Pattern pattern, String string)
{
    Matcher matcher = pattern.matcher(string);

    int count = 0;
    int pos = 0;
    while (matcher.find(pos))
    {
        count++;
        pos = matcher.start() + 1;
    }

    return count;
}


示例调用:

Pattern pattern = Pattern.compile("232");
int count = countMatches(pattern, "23232"); // Returns 2


如果要进行非正则表达式搜索,只需使用LITERAL标志适当地编译模式:

Pattern pattern = Pattern.compile("1+1", Pattern.LITERAL);
int count = countMatches(pattern, "1+1+1"); // Returns 2


评论


是的。令人惊讶的是,Apache StringUtils中没有这样的东西。

–麦克·啮齿动物
17年1月22日在11:53

#11 楼

您可以使用内置的库函数来出现次数:

import org.springframework.util.StringUtils;
StringUtils.countOccurrencesOf(result, "R-")


评论


不起作用,您应该指定使用的依赖项。

– Saikat
16年5月30日在7:39

#12 楼

每当您寻找下一个出现时,就增加lastIndex

否则,总是会找到第一个子字符串(在位置0)。

#13 楼

public int indexOf(int ch,
                   int fromIndex)


返回第一次出现的指定字符在此字符串中的索引,从指定的索引开始搜索。

因此,您的lastindex值始终为0,并且始终在字符串中查找问候。

#14 楼

给出的正确答案不利于计算行返回之类的内容,而且过于冗长。以后的答案比较好,但都可以使用

str.split(findStr).length


使用问题中的示例删除尾随匹配。

评论


这已经在另一个答案中讨论了;这个答案也做得更好。

–michaelb958--GoFundMonica
13年7月3日于13:52

这应该是对有问题的答案的评论,而不是其他答案。

–james.garriss
2014年1月24日19:05

#15 楼

尝试将lastIndex+=findStr.length()添加到循环的末尾,否则将陷入无穷循环,因为一旦找到子字符串,便会尝试从相同的最后位置一次又一次地找到它。

#16 楼

试试这个。它用-替换所有匹配项。

String str = "helloslkhellodjladfjhello";
String findStr = "hello";
int numberOfMatches = 0;
while (str.contains(findStr)){
    str = str.replaceFirst(findStr, "-");
    numberOfMatches++;
}


如果不想破坏str,则可以创建具有相同内容的新字符串:

String str = "helloslkhellodjladfjhello";
String strDestroy = str;
String findStr = "hello";
int numberOfMatches = 0;
while (strDestroy.contains(findStr)){
    strDestroy = strDestroy.replaceFirst(findStr, "-");
    numberOfMatches++;
}


执行此块后,这些将是您的值:

str = "helloslkhellodjladfjhello"
strDestroy = "-slk-djladfj-"
findStr = "hello"
numberOfMatches = 3


#17 楼

正如@Mr_and_Mrs_D建议的那样:

String haystack = "hellolovelyworld";
String needle = "lo";
return haystack.split(Pattern.quote(needle), -1).length - 1;


#18 楼

根据现有的答案,我想添加一个没有if的“简短版本”:

String str = "helloslkhellodjladfjhello";
String findStr = "hello";

int count = 0, lastIndex = 0;
while((lastIndex = str.indexOf(findStr, lastIndex)) != -1) {
    lastIndex += findStr.length() - 1;
    count++;
}

System.out.println(count); // output: 3


评论


如果字符串重复,则需要考虑这一点,例如,如果要在字符串“ xxx”中查找字符串“ xx”。

–tCoe
16-9-29在21:23

#19 楼

这是用于计算令牌在用户输入的字符串中出现了多少次的高级版本:

public class StringIndexOf {

    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);

        System.out.println("Enter a sentence please: \n");
        String string = scanner.nextLine();

        int atIndex = 0;
        int count = 0;

        while (atIndex != -1)
        {
            atIndex = string.indexOf("hello", atIndex);

            if(atIndex != -1)
            {
                count++;
                atIndex += 5;
            }
        }

        System.out.println(count);
    }

}


#20 楼

下面的方法显示整个字符串重复多少次子字符串。希望对您有用:-

    String searchPattern="aaa"; // search string
    String str="aaaaaababaaaaaa"; // whole string
    int searchLength = searchPattern.length(); 
    int totalLength = str.length(); 
    int k = 0;
    for (int i = 0; i < totalLength - searchLength + 1; i++) {
        String subStr = str.substring(i, searchLength + i);
        if (subStr.equals(searchPattern)) {
           k++;
        }

    }


#21 楼

这是不使用regexp / patterns / matchers甚至不使用StringUtils的另一种解决方案。

String str = "helloslkhellodjladfjhelloarunkumarhelloasdhelloaruhelloasrhello";
        String findStr = "hello";
        int count =0;
        int findStrLength = findStr.length();
        for(int i=0;i<str.length();i++){
            if(findStr.startsWith(Character.toString(str.charAt(i)))){
                if(str.substring(i).length() >= findStrLength){
                    if(str.substring(i, i+findStrLength).equals(findStr)){
                        count++;
                    }
                }
            }
        }
        System.out.println(count);


#22 楼

如果需要原始字符串中每个子字符串的索引,则可以使用indexOf进行如下操作:

 private static List<Integer> getAllIndexesOfSubstringInString(String fullString, String substring) {
    int pointIndex = 0;
    List<Integer> allOccurences = new ArrayList<Integer>();
    while(fullPdfText.indexOf(substring,pointIndex) >= 0){
       allOccurences.add(fullPdfText.indexOf(substring, pointIndex));
       pointIndex = fullPdfText.indexOf(substring, pointIndex) + substring.length();
    }
    return allOccurences;
}


#23 楼

public static int getCountSubString(String str , String sub){
int n = 0, m = 0, counter = 0, counterSub = 0;
while(n < str.length()){
  counter = 0;
  m = 0;
  while(m < sub.length() && str.charAt(n) == sub.charAt(m)){
    counter++;
    m++; n++;
  }
  if (counter == sub.length()){
    counterSub++;
    continue;
  }
  else if(counter > 0){
    continue;
  }
  n++;
}

return  counterSub;


}

评论


这个问题已有8年历史了,并且没有任何迹象表明为什么这是比其他22个解决方案更好的解决方案,应该将其删除。

–詹森·惠勒(Jason Wheeler)
17年11月29日在23:36

#24 楼

此解决方案打印整个字符串中给定子字符串出现的总数,还包括存在重叠匹配的情况。

class SubstringMatch{
    public static void main(String []args){
        //String str = "aaaaabaabdcaa";
        //String sub = "aa";
        //String str = "caaab";
        //String sub = "aa";
        String str="abababababaabb";
        String sub = "bab";

        int n = str.length();
        int m = sub.length();

        // index=-1 in case of no match, otherwise >=0(first match position)
        int index=str.indexOf(sub), i=index+1, count=(index>=0)?1:0;
        System.out.println(i+" "+index+" "+count);

        // i will traverse up to only (m-n) position
        while(index!=-1 && i<=(n-m)){   
            index=str.substring(i, n).indexOf(sub);
            count=(index>=0)?count+1:count;
            i=i+index+1;  
            System.out.println(i+" "+index);
        }
        System.out.println("count: "+count);
    }
}