了解 Java 中的子字符串:基本指南

深入理解Java中的子字符串操作

本文旨在帮助大家深入理解 Java 中子字符串的概念及其应用。除了理论知识,我们还会通过具体的代码示例来辅助理解,教你如何创建子字符串,并在字符串中查找子字符串,让抽象的概念变得生动形象。

在深入学习之前,我们首先要了解子字符串的基础知识。

什么是字符串和子字符串?

在Java中,字符串被定义为一系列字符的序列。每一个字符串都是一个对象。Java中的字符串可以包含各种字符,例如字母、数字、符号甚至是空格。而子字符串则是指包含在一个较大字符串中的一部分字符序列,它是字符串的子集。

例如,“Geek”可以看作是字符串“techblik.com”的一个子字符串。使用子字符串,我们可以提取字符串中的特定片段。

例如,假设你有一个名字“John Doe”,如果你只想提取“John”,就可以使用子字符串轻松实现。 此外,如果你有一个名字列表“John, Jack, Jolly”,并且想确认“John”是否在其中,子字符串也能派上用场。 以上只是子字符串的一些应用场景,一旦你掌握了它,就能在各种操作中灵活运用。

现在,我们已经对Java中子字符串的概念有了一定的了解。接下来,让我们看看如何在Java中创建和使用它们。

#1. 利用`substring()`方法

`substring()`方法是创建子字符串的利器。它接受一个或两个参数作为输入,分别是起始索引 `startIndex` 以及可选的结束索引 `endIndex`,最终返回我们所需要的子字符串。

根据参数的个数,`substring()`方法有两种使用方式。下面让我们详细了解一下。

`substring(int startIndex)`

第一种形式是 `substring(startIndex)`。该方法接受一个整数值作为参数,这个整数代表子字符串的起始位置。它返回从给定的起始索引开始直到原始字符串末尾的子字符串。

下面是一个代码示例:

public class Substrings{
    public static void main(String args[]){
        String str="techblik.com";
        System.out.println("原始字符串: " + str);
        System.out.println("子字符串: " +str.substring(4)); //字符串索引从0开始
    }
}

输出结果如下:

原始字符串: techblik.com
子字符串: blik.com

从输出结果可以看出,原始字符串是“techblik.com”,而返回的子字符串是“blik.com”。它从索引为4的位置(即第5个字符)开始,截取到字符串的末尾。

`substring(int startIndex, int endIndex)`

这是使用 `String` 类的 `substring` 方法的另一种方式。我们可以向 `substring` 方法传递两个整数:起始索引和结束索引。它的格式为`substring(startIndex, endIndex)`。

为了更深入地理解,我们来看一些代码示例:

public class Substrings{
    public static void main(String args[]){
        String str="GeekFlareFans";
        System.out.println("原始字符串: " + str);
        System.out.println("子字符串: " +str.substring(4,9));  //获取索引为4到8的子字符串

    }
}

输出结果为:

原始字符串: GeekFlareFans
子字符串: Flare

如你所见,给定字符串“GeekFlareFans”,输出的子字符串为“Flare”。我们传递的起始索引为4,结束索引为9。它从索引为4的元素开始,到索引为9之前结束。需要注意的是,它不包括结束索引对应的元素。它返回的子字符串包含了结束索引之前的所有元素,但不包含结束索引处的元素。

#2. 利用`split()`方法

`split()`方法是Java中`String`类的另一个非常有用的方法,它可以帮助我们创建子字符串。当我们需要处理包含用公共分隔符分隔的多条信息的字符串时,这个方法非常实用。

语法中提到了“正则表达式”这个术语,这可能会让你感到有些困惑,所以我们先来了解一下正则表达式。正则表达式是“Regular Expression”的缩写,它是一系列用于描述字符串或文本模式的字符序列。在`split`方法的上下文中,正则表达式就是我们的分隔符。

`split()`方法最多接受两个参数作为输入,分别是正则表达式字符串和限制整数。正则表达式是分隔符,当找到分隔符时,原始字符串会被分割成两部分:分隔符之前的部分和分隔符之后的部分。

例如,假设我们要用正则表达式“bcd”来分割字符串“abcdef”,那么我们会得到两个子字符串“a”和“ef”。

该方法返回一个包含分割后字符串的数组。我们可以只指定正则表达式,也可以同时指定正则表达式和限制。下面我们分别了解该方法的各种调用方式。

`split(String regex)`

第一种方法仅接收一个正则表达式字符串,格式为`split(regex)`。它没有限制参数,因此返回数组中所有分隔的子字符串。

让我们通过一些代码来更清晰地理解:

public class Substrings{
    public static void main(String args[]){
        String str="Geek%Flare";
        String[] substrings=str.split("%");
        System.out.println("原始字符串: " + str);
        System.out.println("第一个子字符串: " + substrings[0]);
        System.out.println("第二个子字符串: " + substrings[1]);

    }
}

输出结果如下:

原始字符串: Geek%Flare
第一个子字符串: Geek
第二个子字符串: Flare

正如我们从代码中看到的那样,给定的字符串包含一个分隔符正则表达式“%”。分隔符不一定是单个字符,它可以是包含任意数量字符的任何字符串。 `split()`方法会忽略这个正则表达式,并返回所有由这个正则表达式分隔的子字符串。这些子字符串会被存储在数组中。

在示例代码中,给定的字符串是“Geek%Flare”。因此,我们得到了一个包含两个元素的数组,分别是“Geek”和“Flare”。然后我们通过它们的索引(分别为0,1)访问它们,并将“Geek”和“Flare”打印到控制台。

这里我们还需要注意,如果方法没有传递任何参数,将会抛出一个错误。但是,如果我们传递一个空字符串(””)作为正则表达式,那么我们会得到每一个单独的字符作为子字符串。让我们通过示例来验证。

import java.util.Arrays;

public class Substrings{
    public static void main(String args[]){
        String str="Geek%Flare";
        String[] substrings=str.split("");
        System.out.println(Arrays.toString(substrings));

    }
}

输出结果为:

[G, e, e, k, %, F, l, a, r, e]

如示例所示,当正则表达式参数为空字符串时,它会返回所有字符作为单独的子字符串,我们可以通过打印`split()`方法输出的数组清楚地看到这一点。

`split(String regex, int limit)`

使用该方法的第二种变体,我们可以更好地控制输出,并且可以进一步微调`split()`方法的输出。在这种情况下,`split()`方法接受两个参数作为输入。除了正则表达式,我们还会以`split(regex, limit)`的格式给出一个限制参数。

这里的`limit`指的是输出结果字符串的数量。根据`limit`值的不同,存在三种可能性:

情况 1: 如果 `limit > 0`,则结果数组将包含输出,但分割操作最多会执行 `limit-1` 次。在这种情况下,结果数组包含的元素不会超过指定的限制,并且所有未分割的剩余字符串会原样存储。让我们用代码来更好地理解。

import java.util.Arrays;

public class Substrings{
    public static void main(String args[]){
        String str="Geek%Flare%is%the%best";
        String[] substrings=str.split("%",2);
        System.out.println(Arrays.toString(substrings));

    }
}

输出结果为:

[Geek, Flare%is%the%best]

查看输出结果,我们发现数组中只有两个元素,也就是 `limit` 参数中指定的数字。另外需要注意的是,分割操作只执行了一次,即 `limit – 1`次。

然而,如果正则表达式连续出现两次(”%%”),那么将会产生一个空的子字符串。下面的代码可以帮助你更好地理解:

import java.util.Arrays;

public class Substrings{
    public static void main(String args[]){
        String str="Geek%Flare%is%%the%best%%%";
        String[] substrings=str.split("%",5);
        System.out.println(Arrays.toString(substrings));

    }
}

输出结果如下:

[Geek, Flare, is, , the%best%%%]

基本上,如果 “%” 后面跟着另一个 “%” 或者字符串的结尾,它就会被转换成一个空子字符串。

情况 2: 如果 `limit < 0`,分割操作将会执行尽可能多的次数,对数组大小没有任何限制,但如果正则表达式连续出现两次(“%%”),则数组中会包含空子字符串。

import java.util.Arrays;

public class Substrings{
    public static void main(String args[]){
        String str="Geek%Flare%is%%the%best%%%";
        String[] substrings=str.split("%",-1);
        System.out.println(Arrays.toString(substrings));

    }
}

输出结果为:

[Geek, Flare, is, , the, best, , , ]

从输出中可以看到,分割操作执行了尽可能多的次数,并且还存在空子字符串。

情况 3: 如果 `limit = 0`,分割操作也会执行尽可能多的次数,但这里字符串末尾的所有空子字符串都将从数组中被丢弃。

import java.util.Arrays;

public class Substrings{
    public static void main(String args[]){
        String str="Geek%Flare%is%%the%best%%%";
        String[] substrings=str.split("%",0);
        System.out.println(Arrays.toString(substrings));

    }
}

输出结果如下:

[Geek, Flare, is, , the, best]

我们可以看到,当 `limit = -1` 和 `limit = 0` 时,输出结果非常相似,但是缺少了末尾的空子字符串。换句话说,子字符串数组末尾的空子字符串被忽略了。

另外需要注意的是,如果字符串中不存在正则表达式,它将返回整个原始字符串作为结果。

查找字符串是否包含子字符串

除了从现有字符串创建子字符串外,我们还可以判断一个字符串是否包含特定的子字符串。这在很多场景下都非常有用。那么,如何实现呢?有很多方法可以帮助我们实现这一目标。让我们逐一分析。

利用`contains()`方法

我们可以使用`contains()`方法轻松确定子字符串是否存在。 `String` 类的这个方法接受一个字符串作为输入,也就是我们需要查找的子字符串,并返回一个布尔值,表示子字符串是否在原始字符串中。此方法可以在 `if-else` 块、三元运算符和其他各种场景中使用来实现复杂的逻辑。

让我们更深入地了解一下这个方法。

public class Substrings{
    public static void main(String args[]){
        String str="techblik.com";
        System.out.println("是否包含 Flare? \n"+ str.contains("blik"));
    }
}

输出结果为:

是否包含 Flare?
true

这段代码检查字符串“techblik.com”中是否包含“blik”,成功找到后,它返回一个布尔值“true”,从而确认了子字符串的存在。

public class Substrings{
    public static void main(String args[]){
        String str="techblik.com";
        System.out.println("是否包含 Flare? \n"+ str.contains("Flare1"));
    }
}

输出结果为:

是否包含 Flare?
false

从示例中我们了解到,如果子字符串不在原始字符串中,该方法将返回 `false` 以表示其不存在。这样我们就可以很容易地确定子字符串是否存在。

查找子串的位置

#1. 利用`indexOf()`方法

`indexOf()`方法可以用来查找子字符串是否存在,并返回其索引位置。该方法接收一个字符串或字符作为输入,并给出其第一次出现的位置。但是它只能返回第一次出现的索引,并不能确认是否还有其他出现的情况。另一个需要注意的是,如果子字符串不存在,该方法会返回`-1`。

下面让我们进一步探讨一下这个方法。

public class Substrings{
    public static void main(String args[]){
        String str="GeekFlareGeekFlare";
        System.out.println("Flare的索引: "+ str.indexOf("Flare"));
    }
}

输出结果为:

Flare的索引: 4

在示例中,子字符串“Flare”第一次出现在字符串“GeekFlareGeekFlare”的索引为4的位置。因此,该函数按照预期返回了索引。

#2. 利用`lastIndexOf()`方法

`lastIndexOf()`方法与`indexOf()`方法非常相似。这两种方法都接受子字符串作为输入,并返回其位置的索引。当在指定的字符串中找不到子字符串时,它们的返回值也是相同的,都会返回`-1`。

但是,`indexOf()`方法返回子字符串第一次出现的索引,而`lastIndexOf()`方法返回子字符串最后一次出现的位置。

让我们通过代码看看它的实际效果:

public class Substrings{
    public static void main(String args[]){
        String str="GeekFlareGeekFlare";
        System.out.println("Flare最后一次出现的索引: "+ str.lastIndexOf("Flare"));
    }
}

输出结果为:

Flare最后一次出现的索引: 13

观察输出结果,我们了解到`lastIndexOf()`方法按照预期执行,并且我们获取了子字符串“Flare”在字符串“GeekFlareGeekFlare”中最后一次出现的索引。

常见问题解答

如何使用`split()`方法创建非空的子字符串?

如果主字符串中存在多个正则表达式字符串的实例(例如,“Hello%%Hi”,正则表达式为“%”),`split()`方法会将第一个实例作为分隔符,而其余的实例会输出空字符串。为了解决这个问题,我们可以将限制参数指定为 0。这样它只会给出非空的字符串作为输出。

`indexOf()`方法是否返回子字符串所有实例的索引?

否,`indexOf()`方法不会返回子字符串所有实例的索引。使用`indexOf()`,我们会得到一个整数返回值,其中包含了子字符串第一次出现的索引。但如果找不到子字符串,该方法会返回-1。

如果字符串中不存在给定的索引,`substring()`方法会返回什么?

如果字符串中不存在给定的起始索引和结束索引,编译器会抛出一个错误,也就是 “java.lang.StringIndexOutOfBoundsException:”,并且程序根本不会执行。

结论

在本文中,我们讨论了关于如何使用子字符串的各种方法和关键要点。我们探讨了如何创建子字符串,以及如何检查字符串中是否存在特定的子字符串。这将帮助你更好地理解如何使用子字符串。请多加练习,以全面掌握子字符串的运用。

接下来,你可以查看我们的 Java面试问题列表