HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Checking whether a string contains a substring only once

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
oncesubstringcheckingcontainsonlywhetherstring

Problem

I want to check if a string contains only a single occurrence of the given substring (so the result of containsOnce("foo-and-boo", "oo") should be false). In Java, a simple and straightforward implementation would be either

boolean containsOnce(final String s, final CharSequence substring) {
    final String substring0 = substring.toString();
    final int i = s.indexOf(substring0);
    return i != -1 && i == s.lastIndexOf(substring0);
}


or

boolean containsOnce(final String s, final CharSequence substring) {
        final String substring0 = substring.toString();
        final int i = s.indexOf(substring0);
        if (i == -1) {
            return false;
        }

        final int nextIndexOf = s.indexOf(substring0, i + 1);
        return nextIndexOf == 0 || nextIndexOf == -1; // nextIndexOf is 0 if both arguments are empty strings.
}


Can you suggest a simpler/more efficient implementation?

Solution

Perhaps using pattern matching. It looks more readable to me, but I have no idea about which is more efficient.

public static boolean containsOnce(final String s, final CharSequence substring) {
    Pattern pattern = Pattern.compile(substring.toString());
    Matcher matcher = pattern.matcher(s);
    if(matcher.find()){
        return !matcher.find();
    }
    return false;
}

public static void main(String[] args) throws Exception {
    System.out.println(containsOnce("aba","a"));    //false
    System.out.println(containsOnce("abab", "ab")); //false
    System.out.println(containsOnce("aba", "b"));   //true
    System.out.println(containsOnce("aaa", "aa"));  //true
    System.out.println(containsOnce("",""));        //true
    System.out.println(containsOnce("ab",""));      //false
}


Also note that containsOnce("aaa","aa") returns true. Not sure if you would count this as correct or not.

Note: you can also write it as

Pattern pattern = Pattern.compile(substring.toString());
Matcher matcher = pattern.matcher(s);
return matcher.find() && !matcher.find();


I don't know which of the two is more readable.

EDIT:

After looking up whichever is faster: indexof vs matcher

It seems to be the general consensus that indexof is a bit faster, but that we're talking about such low times that it really doesn't matter much.

Go for whichever solution you prefer I guess ...

Code Snippets

public static boolean containsOnce(final String s, final CharSequence substring) {
    Pattern pattern = Pattern.compile(substring.toString());
    Matcher matcher = pattern.matcher(s);
    if(matcher.find()){
        return !matcher.find();
    }
    return false;
}

public static void main(String[] args) throws Exception {
    System.out.println(containsOnce("aba","a"));    //false
    System.out.println(containsOnce("abab", "ab")); //false
    System.out.println(containsOnce("aba", "b"));   //true
    System.out.println(containsOnce("aaa", "aa"));  //true
    System.out.println(containsOnce("",""));        //true
    System.out.println(containsOnce("ab",""));      //false
}
Pattern pattern = Pattern.compile(substring.toString());
Matcher matcher = pattern.matcher(s);
return matcher.find() && !matcher.find();

Context

StackExchange Code Review Q#161386, answer score: 3

Revisions (0)

No revisions yet.