9

I am writing a method which will return true if either of the Strings appear at the very end of the other String, and the Strings are different. We cannot use endsWith()

For example:

  • if a = "all" and b = "ball", the method would return true.

  • if a = "yes" and b = "yes", the method would return false.

Here's what I have so far but it keeps saying string index out of range= -1

public static boolean startOther(String a, String b){
    if(a.equals(b))
        return false;
    int pos=a.indexOf(b);
    int pos1=b.indexOf(a);
    int len=a.length();
    int len1=b.length();
    if(pos>-1 && a.substring(len-pos).equals(b)|| pos1>-1 && b.substring(len1-pos1).equals(a))
        return true;
    return false;
}
2
  • 3
    Hint: docs.oracle.com/javase/7/docs/api/java/lang/… Commented Sep 26, 2015 at 19:29
  • 1
    Regarding the error: if a doesn't contain b, pos is -1, and you're thus then doing a.substring(len + 1), which thus asks for an index out of the bounds of the string. A debugger would have shown that instantly. You should learn using it. Commented Sep 26, 2015 at 19:37

4 Answers 4

4

A combination of length() and regionMatches(int toffset, String other, int ooffset, int len) should be quite efficient:

public static boolean startOther(final String a, final String b) {
    final int aLength = a.length();
    final int bLength = b.length();
    return aLength != bLength && (aLength > bLength ? a.regionMatches(aLength - bLength, b, 0, bLength)
                                                    : b.regionMatches(bLength - aLength, a, 0, aLength));
}
Sign up to request clarification or add additional context in comments.

Comments

2

It's a bit of "look before you leap", but what you want to do is:

  • Check the index location of each string within another.
  • If (and only if) the index location exists, check to see if the substring from that index spot all the way to the end matches.
  • Otherwise, return false.

If you do any sort of subtraction, you're not going to get the correct size of substring; that is, if you subtract the length of the string you're checking against, you're only going to get one character.

public static boolean startOther(String left, String right) {
    if (left == null || right == null || left.equals(right)) {
        return false;
    }
    int rightSubstringInLeft = left.indexOf(right);
    int leftSubstringInRight = right.indexOf(left);

    if(rightSubstringInLeft != -1) {
        return left.substring(rightSubstringInLeft).equals(right);
    } else if(leftSubstringInRight != -1) {
        return right.substring(leftSubstringInRight).equals(left);
    } else {
        return false;
    }
}

Here's a more optimized form of the same code, as pointed out in the comments. Fundamentally it's the same, but you don't need to perform another equals check on the substring, since lastIndexOf would only ever give you the last index of the whole substring.

public static boolean startOther(String left, String right) {
    if (left == null || right == null || left.equals(right)) {
        return false;
    }
    int rightSubstringInLeft = left.lastIndexOf(right);
    int leftSubstringInRight = right.lastIndexOf(left);

    if(rightSubstringInLeft != -1) {
        return rightSubstringInLeft == left.length() - right.length();
    } else if(leftSubstringInRight != -1) {
        return leftSubstringInRight == right.length() - left.length();
    } else {
        return false;
    }
}

5 Comments

That's quite inefficient. Why not use a.lastIndexOf(b), and check that the returned index is a.length() - b.length()? Or using a.lastIndexOf(b, a.length() - b.length()), and check that the returned value is 0? Checking for substring equality is redundant, since lastIndexOf() already does it.
String#lastIndexOf doesn't do what you believe it should do in this scenario. You're expected to pass in a Unicode point to that method as opposed to an integer of any kind.
There are several lastIndexOf() methods: docs.oracle.com/javase/7/docs/api/java/lang/… and docs.oracle.com/javase/7/docs/api/java/lang/… are the ones I'm talking about
Fair point. So, I went with the above approach because it's simpler to understand. I respect and acknowledge that optimizations exist and should be taken, but I'm not overly bothered with it.
I personally find it more natural to find the last index of the substring, and check that it's at the very end, rather than finding the first index of the substring, and checking if there is another such substring at the end. The indexOf is useless. You could just check that the b.length() last characters of a are equal to b, without calling indexOf. But anyway, the exercise is pointless, since endsWith exists and should be used.
1

Since you can't use endsWith, first test for null. Then get the lengths. Test that they aren't the same. Check the indexOf + length is equal for true. Something like

public static boolean startOther(String a, String b) {
    if (a == null || b == null) return false;
    int aLen = a.length();
    int bLen = b.length();
    if (aLen != bLen) {
        if (aLen < bLen) {
            int p = b.indexOf(a);
            return p != -1 && p + aLen == bLen;
        } else {
            int p = a.indexOf(b);
            return p != -1 && p + bLen == aLen;
        }
    }
    return false;
}

which I tested like

public static void main(String[] args) {
    System.out.println(startOther("all", "ball"));
    System.out.println(startOther("yes", "yes"));
}

and got the (requested) output

true
false

1 Comment

Or simply: return (a.length() != b.length()) && (a.endsWith(b) || b.endsWith(a)), which should be faster since it doesn't have to check for equality.
1
indexOf(String s)

Returns: the index of the first occurrence of the specified substring, or -1 if there is no such occurrence.

If indexOf() returned -1 and you call a.substring(len-pos), the parameter will be len - (-1) = len + 1. That's the cause of out of range.

This case happens always in your code, because of two mirror lines:

int pos=a.indexOf(b);
int pos1=b.indexOf(a);

If you checked equals before method call, one of pos always will became -1. It is obvious: if one string contains another, and they are not equal, then the second string doesn't contain first.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.