在Java中比较子字符串

9
我正在编写一个方法,如果两个字符串中的任意一个出现在另一个字符串的末尾并且这两个字符串不同,则返回true。我们不能使用endsWith()。
例如:
- 如果a = "all"和b = "ball",则该方法将返回true。 - 如果a = "yes"和b = "yes",则该方法将返回false。
以下是我到目前为止的代码,但它一直显示字符串索引超出范围= -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;
}

3
好的,我会尽力为您翻译。以下是需要翻译的内容:提示:http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#endsWith%28java.lang.String%29 - JB Nizet
1
关于错误:如果a不包含b,则pos为-1,因此您随后执行a.substring(len + 1),这样会请求字符串超出范围的索引。调试器将立即显示它。您应该学会使用它。 - JB Nizet
4个回答

4

length()regionMatches(int toffset, String other, int ooffset, int len)结合起来使用应该会非常高效:

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));
}

2

这是一个“三思而后行”的过程,你需要做的是:

  • 检查每个字符串在另一个字符串中的索引位置。
  • 如果(仅当)索引位置存在,则检查从该索引位置一直到末尾的子字符串是否匹配。
  • 否则,返回false。

如果你进行任何形式的减法运算,你将无法得到正确的子字符串大小;也就是说,如果你从正在检查的字符串长度中减去,你只会得到一个字符。

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;
    }
}

以下是评论中指出的更优化的代码形式。从根本上讲,它与原始代码相同,但您不需要对子字符串执行另一个等于检查,因为 lastIndexOf 只会给出整个子字符串的最后一个索引。

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;
    }
}

这非常低效。为什么不使用a.lastIndexOf(b)并检查返回的索引是否为a.length() - b.length()?或者使用a.lastIndexOf(b, a.length() - b.length()),并检查返回值是否为0?检查子字符串相等是多余的,因为lastIndexOf()已经检查了它。 - JB Nizet
String#lastIndexOf 在这种情况下并不像你所想的那样运行。你需要传递一个Unicode编码点给该方法,而不是任何类型的整数。 - Makoto
有几个lastIndexOf()方法:http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#lastIndexOf%28java.lang.String%29 和 http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#lastIndexOf%28java.lang.String,%20int%29 是我所说的那些。 - JB Nizet
公正的观点。因此,我选择了上述方法,因为它更容易理解。我尊重并承认优化的存在和必要性,但我并不过于担心它。 - Makoto
我个人认为,找到子字符串的最后一个索引,并检查它是否在末尾更自然,而不是找到子字符串的第一个索引,并检查是否还有另一个这样的子字符串在末尾。indexOf 是无用的。你可以只检查 a 的 b.length() 个字符是否等于 b,而不调用 indexOf。但无论如何,这个练习都是没有意义的,因为 endsWith 存在并应该被使用。 - JB Nizet

1

由于无法使用endsWith,首先测试null。然后获取长度。检查它们是否不同。检查true的indexOf + length是否相等。类似以下内容:

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;
}

我测试过的代码如下:

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

并且获得了(请求的)输出

true
false

1
或者简单地写成:return (a.length() != b.length()) && (a.endsWith(b) || b.endsWith(a)),这样会更快,因为它不需要检查相等性。 - JB Nizet

1
indexOf(String s)
返回值:指定子字符串第一次出现的索引,如果没有出现则返回-1。

如果indexOf()返回-1并且您调用a.substring(len-pos),则参数将为len - (-1) = len + 1。这就是越界的原因。

这种情况在您的代码中总是发生,因为有两行镜像:

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

如果在方法调用之前检查了相等,那么pos中的一个将始终变为-1。这是显而易见的:如果一个字符串包含另一个字符串,并且它们不相等,则第二个字符串不包含第一个字符串。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接