前言
本文主要介绍了字符串类String的概述和使用,包括String类的概念和构造方法、String常用的成员方法及使用和正则表达式的概念和使用等部分。
1.String类的概念和构造方法
(1)String类和常量池的概念
java.lang.String
类用于描述字符串,Java程序中所有的字符串字面值 (直接量)都可以使用该类的对象加以描述,如"abc"
。
该类由final关键字修饰,表示该类不能被继承 ;
继承自Object类,重写了Object类中的方法,同时实现了Serializable
、Comparable<String>
和CharSequence
接口;
从jdk1.9开始该类的底层不使用char[]
来存储数据,而是改成 byte[]
加上编码标记,从而节约了一些空间。
从源码中可以看到,定义字符数组的格式为private final byte[] value;
,被final关键字修饰,说明数组引用不能改变指向,指向的一维数组的长度不能改变,所以String类描述的字符串内容是常量 、不可更改,因此可以被共享使用 。
举例如下:
String str1 = "abc"; // 其中"abc"这个字符串是个常量不可改变
str1 = "123"; // 将"123"字符串的地址赋值给变量str1
其中,"abc"
是常量、不可改变,保存在方法区;
上面的操作改变了str1的指向到字符串对象"123"
,但是并没有改变原来指向的内容"abc"
;
此时没有引用指向"abc"
,此时会自动触发JVM中的垃圾回收机制、回收释放对应的内存空间。
由于String类型描述的字符串内容是常量不可改变,因此Java虚拟机将首次出现的字符串放入常量池 中,若后续代码中出现了相同字符串内容则直接使用池中已有的字符串对象而无需重复申请内存及创建对象,从而提高了性能。
现在验证常量池如下:
package com.stage1.module3;
/**
* @author Corley
* @date 2021/7/20 10:24
* @description javase-com.stage1.module3
*/
public class StringPoolTest {
public static void main(String[] args) {
// 验证String常量池
String s1 = "abc";
String s2 = "abc";
System.out.println(s1 == s2);
}
}
输出:
true
可以看到,s1 == s2
的值为true,说明s1和s2的地址相同,也就说明了它们属于同一个对象,都存在于常量池中。
到目前为止,只有String这个特殊类除了new的方式还可以直接通过字符串赋值来创建对象(包装类除外)。
(2)String类常用构造方法的使用
String类常用的构造方法如下:
方法声明 | 功能介绍 |
---|---|
String() | 使用无参方式构造对象得到空字符序列 |
String(byte[] bytes, int offset, int length) | 使用bytes数组中下标从offset位置开始的length个字节来构造对象 |
String(byte[] bytes) | 使用bytes数组中的所有内容构造对象 |
String(char[] value, int offset, int count) | 使用value数组中下标从offset位置开始的count个字符来构造对象 |
String(char[] value) | 使用value数组中的所有内容构造对象 |
String(String original) | 根据参数指定的字符串内容来构造对象,新创建对象为参数对象的副本 |
现在使用String类的构造方法创建字符串,如下:
package com.stage1.module3;
/**
* @author Corley
* @date 2021/7/20 12:36
* @description javase-com.stage1.module3
*/
public class StringConstructorTest {
public static void main(String[] args) {
// 1.使用无参构造方式构造对象
String str1 = new String();
System.out.println("str1 = " + str1); // ""
System.out.println("-----------------------------------");
// 2.使用参数指定的byte数组来构造对象
byte[] bArr = {65, 66, 67, 97, 98, 99};
// 使用字节数组中的一部分元素构造字符串对象,这里是使用数组bArr中洗标从1开始的3个字符构造字符串对象
String str2 = new String(bArr, 1, 3);
System.out.println("str2 = " + str2); // BCa
// 使用整个字符数组来构造字符串对象
String str3 = new String(bArr);
System.out.println("str3 = " + str3); // ABCabc
System.out.println("-----------------------------------");
// 3.使用字符数组构造字符串对象
char[] cArr = {'H', 'e', 'l', 'l', 'o'};
// 使用字符数组中的一部分元素构造对象
String str4 = new String(cArr, 2, 3); // llo
System.out.println("str4 = " + str4);
// 使用整个字符数组构造字符串对象
String str5 = new String(cArr);
System.out.println("str5 = " + str5); // Hello
System.out.println("-----------------------------------");
// 4.使用字符串来构造字符串对象
String str6 = new String("world");
System.out.println("str6 = " + str6); // world
}
}
输出:
str1 =
-----------------------------------
str2 = BCa
str3 = ABCabc
-----------------------------------
str4 = llo
str5 = Hello
-----------------------------------
str6 = world
其中,String str1 = new String();
的结果是""
空字符串,即空字符串对象、有对象只是内容为空,而不是null,null表示空、连对象都没有;
String str2 = new String(bArr, 1, 3);
和String str3 = new String(bArr);
构造字符串的原理是将对应的每个整数转换成对应的字符,再将所有的字符拼接成字符串;
String str4 = new String(cArr, 2, 3);
和String str5 = new String(cArr);
构造字符串的思路是直接将字符拼接起来组成字符串。
(3)String类的笔试考点
1.请问下面的代码会创建几个对象,分别存在什么位置?
如下:
// 1.请问下面的代码会创建几个对象,分别存在什么位置?
String str1 = "hello";
String str2 = new String("hello");
其中,String str1 = "hello";
创建1个对象,存放在常量池中;
String str2 = new String("hello");
创建2个对象,一个是字符串直接量hello、存放在常量池,一个是String类型的对象、存放在堆区,引用str2指向堆区。
2.常量池和堆区对象的比较,分析下面代码的执行结果。
如下:
package com.stage1.module3;
/**
* @author Corley
* @date 2021/7/20 13:10
* @description javase-com.stage1.module3
*/
public class StringExamTest {
public static void main(String[] args) {
// 1.请问下面的代码会创建几个对象,分别存在什么位置?
String str1 = "hello"; // 1个对象,存放在常量池中
String str2 = new String("hello"); // 2个对象,一个是字符串直接量hello、存放在常量池,一个是String类型的对象、存放在堆区,引用str2指向堆区
// 2.分析下面代码的执行结果
String str3 = "hello"; // 常量池
String str4 = "hello"; // 常量池
String str5 = new String("hello"); // 堆区
String str6 = new String("hello"); // 堆区
System.out.println(str3 == str4); // 比较地址,true
System.out.println(str3.equals(str4)); // 比较内容,true
System.out.println(str5 == str6); // 比较地址,false
System.out.println(str5.equals(str6)); // 比较内容,true
System.out.println(str3 == str5); // 比较地址,false
System.out.println(str3.equals(str5)); // 比较内容,true
}
}
输出:
true
true
false
true
false
true
其中,==
比较的是两个字符串的地址,equals()
方法比较的是连个字符串的内容,分析各个字符之间的地址、内容关系即可得出答案。
3.常量优化机制,变量不支持优化机制。
package com.stage1.module3;
/**
* @author Corley
* @date 2021/7/20 13:10
* @description javase-com.stage1.module3
*/
public class StringExamTest {
public static void main(String[] args) {
// 1.请问下面的代码会创建几个对象,分别存在什么位置?
String str1 = "hello"; // 1个对象,存放在常量池中
String str2 = new String("hello"); // 2个对象,一个是字符串直接量hello、存放在常量池,一个是String类型的对象、存放在堆区,引用str2指向堆区
// 2.分析下面代码的执行结果
String str3 = "hello"; // 常量池
String str4 = "hello"; // 常量池
String str5 = new String("hello"); // 堆区
String str6 = new String("hello"); // 堆区
System.out.println(str3 == str4); // 比较地址,true
System.out.println(str3.equals(str4)); // 比较内容,true
System.out.println(str5 == str6); // 比较地址,false
System.out.println(str5.equals(str4)); // 比较内容,true
System.out.println(str3 == str5); // 比较地址,false
System.out.println(str3.equals(str5)); // 比较内容,true
System.out.println("---------------------------------------");
// 3.常量有优化机制,变量没有
String str7 = "abcd";
String str8 = "ab" + "cd"; // 常量优化机制
System.out.println(str7 == str8); // 比较地址,true
String str9 = "ab";
String str10 = str9 + "cd"; // 没有常量优化机制
System.out.println(str7 == str10); // 比较地址,false
}
}
输出:
true
true
false
true
false
true
---------------------------------------
true
false
可以看到,存在着常量优化机制,ab
与cd
都是常量、拼接成新的常量abcd
,而abcd
之前已经使用过、保存在常量池中,可以直接使用,不需要再创建新的字符串对象,所以str7和str8指向的是同一个字符串对象,比较地址的结果是相同的;
Java语言为字符串连接运算符(+)提供特殊支持,并将其他对象转换为字符串,所以str9 + "cd"
得到的是字符串abcd
;
str10是通过str9 + "cd"
得到的,虽然与str7的值是相同的,但是因为str9是变量,变量不存在优化机制,所以与str7不是同一个对象、地址不同,返回false。
2.String常用的成员方法及使用
String类常用的成员方法如下:
方法声明 | 功能介绍 |
---|---|
String toString() | 返回字符串本身 |
byte[] getBytes() | 将当前字符串内容转换为byte数组并返回 |
char[] toCharArray() | 用于将当前字符串内容转换为char数组并返回 |
char charAt(int index) | 方法charAt用于返回字符串指定位置的字符 |
int length() | 返回字符串字符序列的长度 |
boolean isEmpty() | 判断字符串是否为空 |
int compareTo(String anotherString) | 用于比较调用对象和参数对象的大小关系 |
int compareToIgnoreCase(String str) | 忽略大小写比较调用对象和参数对象的大小关系,例如’a’和’A’视作相等 |
String concat(String str) | 用于实现字符串的拼接 |
boolean contains(CharSequence s) | 用于判断当前字符串是否包含参数指定的内容 |
String toLowerCase() | 返回字符串的小写形式 |
String toUpperCase() | 返回字符串的大写形式 |
String trim() | 返回去掉前导和后继空白的字符串 |
boolean startsWith(String prefix) | 判断字符串是否以参数字符串开头 |
boolean startsWith(String prefix, int toffset) | 从指定位置开始是否以参数字符串开头 |
boolean endsWith(String suffix) | 判断字符串是否以参数字符串结尾 |
boolean equals(Object anObject) | 用于比较字符串内容是否相等并返回 |
int hashCode() | 获取调用对象的哈希码值 |
boolean equalsIgnoreCase(String anotherString) | 用于比较字符串内容是否相等并返回,不考虑大小写,如’A’和’a’视作相等 |
int indexOf(int ch) | 用于返回当前字符串中参数ch指定字符第一次出现的下标 |
int indexOf(int ch, int fromIndex) | 用于从fromIndex位置开始查找ch指定的字符 |
int indexOf(String str) | 在字符串中检索str第一次出现的位置,若找不到返回-1 |
int indexOf(String str, int fromIndex) | 表示从字符串的fromIndex位置开始检索str第一次出现的位置 |
int lastIndexOf(int ch) | 用于返回参数ch指定的字符最后一次出现的下标 |
int lastIndexOf(int ch, int fromIndex) | 用于从fromIndex位置开始查找ch指定字符最后一次出现的下标 |
int lastIndexOf(String str) | 返回str指定字符串最后一次出现的下标 |
int lastIndexOf(String str, int fromIndex) | 用于从fromIndex位置开始反向搜索指定字符串第一次出现的下标 |
String substring(int beginIndex, int endIndex) | 返回字符串中从下标beginIndex(包括)开始到endIndex(不包括)结束的子字符串 |
String substring(int beginIndex) | 返回字符串中从下标beginIndex(包括)开始到字符串结尾的子字符串 |
(1)String类型和数组之间的转换
String类型与数组之间的转换用到byte[] getBytes()
和char[] toCharArray()
方法。
使用如下:
package com.stage1.module3;
/**
* @author Corley
* @date 2021/7/20 18:27
* @description javase-com.stage1.module3
*/
public class StringByteCharTest {
public static void main(String[] args) {
// 1.创建String类型的对象
String str1 = new String("Corley");
System.out.println("str1 = " + str1);
// 2.String类型转换为byte类型数组
// 实现思路是先将字符串拆分成字符,再将每个字符转换成byte类型
byte[] bArr = str1.getBytes();
for (int i = 0; i < bArr.length; i++) {
System.out.println("下标为" + i + "的编码是" + bArr[i]);
}
// 将byte数组转回String类型
String str2 = new String(bArr);
System.out.println("转回字符串为:" + str2);
System.out.println("----------------------------------");
// 3.String类型转换为char类型数组
// 实现思路是将字符串拆分成字符并保存到数组中
char[] cArr = str1.toCharArray();
for (int i = 0; i < cArr.length; i++) {
System.out.println("下标为" + i + "的字符是" + cArr[i]);
}
// 将char数组转回String类型
String str3 = new String(cArr);
System.out.println("转回字符串为:" + str3);
}
}
输出:
str1 = Corley
下标为0的编码是67
下标为1的编码是111
下标为2的编码是114
下标为3的编码是108
下标为4的编码是101
下标为5的编码是121
转回字符串为:Corley
----------------------------------
下标为0的字符是C
下标为1的字符是o
下标为2的字符是r
下标为3的字符是l
下标为4的字符是e
下标为5的字符是y
转回字符串为:Corley
其中,byte[] bArr = str1.getBytes();
的实现思路是先将字符串拆分成字符,再将每个字符转换成byte类型,也就是获取对应字符的ASCII值;
char[] cArr = str1.toCharArray();
的实现思路是将字符串拆分成字符并保存到数组中。
(2)String类中字符的获取和使用
现在使用char charAt(int index)
、int length()
和boolean isEmpty()
方法,如下:
package com.stage1.module3;
/**
* @author Corley
* @date 2021/7/20 18:44
* @description javase-com.stage1.module3
*/
public class StringCharTest {
public static void main(String[] args) {
// 1.获取String类型的对象
String str1 = new String("Corley");
System.out.println("str1 = " + str1);
// 2.获取字符串的长度和每个字符
System.out.println("字符串长度为:" + str1.length());
System.out.println("下标为0的字符:" + str1.charAt(0));
System.out.println("下标为1的字符:" + str1.charAt(1));
System.out.println("下标为2的字符:" + str1.charAt(2));
System.out.println("下标为3的字符:" + str1.charAt(3));
System.out.println("下标为4的字符:" + str1.charAt(4));
System.out.println("下标为5的字符:" + str1.charAt(5));
// System.out.println("下标为6的字符:" + str1.charAt(6)); // java.lang.StringIndexOutOfBoundsException
System.out.println("----------------------------------");
// 3.使用for循环获取所有字符
for (int i = 0; i < str1.length(); i++) {
System.out.println("下标为" + i + "的字符:" + str1.charAt(i));
}
System.out.println("----------------------------------");
// 4.判断字符串是否为空
System.out.println(0 == str1.length() ? "字符串为空" : "字符串不为空");
System.out.println(str1.isEmpty() ? "字符串为空" : "字符串不为空");
System.out.println("----------------------------------");
// 5.笔试考点
// 使用两种方式实现字符串“12345”转换为整数12345
String str2 = new String("12345");
// 方式一:使用Integer类的parseInt()方法转换
int ia = Integer.parseInt(str2);
System.out.println("转换出来的整数是:" + ia);
// 方式二:利用ASCII来实现类型转换
int ib = 0;
for (int i = 0; i < str2.length(); i++) {
ib = ib * 10 + (str2.charAt(i) - '0');
}
System.out.println("转换出来的整数是:" + ib);
System.out.println("-------------------------------------");
// 6.实现整数到字符串的转换
String str3 = String.valueOf(ib);
System.out.println("str3 = " + str3);
str3 = "" + ib;
System.out.println("str3 = " + str3);
}
}
输出:
str1 = Corley
字符串长度为:6
下标为0的字符:C
下标为1的字符:o
下标为2的字符:r
下标为3的字符:l
下标为4的字符:e
下标为5的字符:y
----------------------------------
下标为0的字符:C
下标为1的字符:o
下标为2的字符:r
下标为3的字符:l
下标为4的字符:e
下标为5的字符:y
----------------------------------
字符串不为空
字符串不为空
----------------------------------
转换出来的整数是:12345
转换出来的整数是:12345
-------------------------------------
str3 = 12345
str3 = 12345
可以看到,如果字符串下标越界,可以通过编译、但是运行会发生异常,例如str.charAt(6)
就会报错java.lang.StringIndexOutOfBoundsException: String index out of range
;
0 == str1.length()
和str1.isEmpty()
的效果是相同的;
String类中的静态方法static String valueOf()
通过重载,实现了将各种类型转化为字符串,例如String.valueOf(ib)
将整型转换为字符串,但是开发中更推荐的是第二种方式"" + ib
,因为字符串与任何类型数据进行拼接得到的都是字符串,而这里拼接的字符串是空字符串,所以变相实现了将整数转换为字符串。
(3)String类对象实现回文的判断
案例题目:
判断字符串“上海自来水来自海上”是否为回文并打印,所谓回文是指一个字符序列无论从左向右读还是从右向左读都是相同的句子。
代码如下:
package com.stage1.module3;
/**
* @author Corley
* @date 2021/7/21 12:50
* @description javase-com.stage1.module3
*/
public class StringPalindromeTest {
public static void main(String[] args) {
// 1.创建字符串对象
String str = new String("上海自来水来自海上");
System.out.println("str = " + str);
// 2.判断字符串是否为回文字符串
for (int i = 0; i < str.length()/2; i++) {
if (str.charAt(i) != str.charAt(str.length()-1-i)) {
System.out.println(str + "不是回文!");
return; // 用于在得到结果时实现方法的结束
}
}
System.out.println(str + "是回文!");
}
}
输出:
str = 上海自来水来自海上
上海自来水来自海上是回文!
可以看到原字符串是回文串。
(4)String类实现字符串之间大小的比较
String类实现字符串之间的大小比较使用int compareTo(String anotherString)
和int compareToIgnoreCase(String str)
方法。
其中,int compareTo(String anotherString)
比较的原理是:
按字典顺序比较两个字符串,即比较基于字符串中每个字符的Unicode值,调用对象对应的字符序列按字典顺序与参数字符串表示的字符序列进行比较。 如果调用对象按字典顺序排在参数字符串之前,则结果为负整数; 如果调用对象按字典顺序在参数字符串之后,则结果为正整数;如果字符串相等,结果为零。
如果两个字符串不同,则要么它们在对两个字符串都是有效索引的某个索引处具有不同的字符,要么它们的长度不同,或者两者都有:
如果它们在一个或多个索引位置具有不同的字符,则令k为最小的索引, compareTo返回两个字符串中位置k处两个字符值的差值,即this.charAt(k)-anotherString.charAt(k)
;
如果它们没有不同的索引位置,那么较短的字符串按字典顺序排在较长的字符串之前, compareTo返回字符串长度的差值,即this.length()-anotherString.length()
。
如下:
package com.stage1.module3;
/**
* @author Corley
* @date 2021/7/21 13:03
* @description javase-com.stage1.module3
*/
public class StringCompareTest {
public static void main(String[] args) {
// 1.构造String类型的对象
String str = new String("Corley");
System.out.println("str = " + str);
// 2.使用构造好的String类型对象与其他字符串之间比较大小
System.out.println(str.compareTo("Jack")); // 'C' - 'J' => 67 - 74 => -7
System.out.println(str.compareTo("Curliy")); // 'o' - 'u' => 111 - 117 => -6
System.out.println(str.compareTo("Conliy")); // 'r' - 'n' => 114 - 110 => 4
System.out.println(str.compareTo("Corley Town")); // 长度:6 - 11 => -5
System.out.println(str.compareTo("corley")); // 'C' - 'c' => 67 - 99 => -32
System.out.println(str.compareToIgnoreCase("corley")); // 0
}
}
输出:
str = Corley
-7
-6
4
-5
-32
0
(5)String类中使用方法操作字符串
现在使用方法来操作和判断字符串,如下:
package com.stage1.module3;
import java.util.Locale;
/**
* @author Corley
* @date 2021/7/22 9:06
* @description javase-com.stage1.module3
*/
public class StringOperationTest {
public static void main(String[] args) {
// 1.构造String类型的对象
String str1 = new String(" You may be out of my sight, but never out of my mind. ");
System.out.println("str1 = " + str1);
System.out.println("-------------------------------------------");
// 2.调用各种方法进行测试
// 判断是否包含某个子串
boolean b1 = str1.contains("sight"); // true,区分大小写
System.out.println("b1 = " + b1);
b1 = str1.contains("Sight"); // false
System.out.println("b1 = " + b1);
// 将字符串转换为大写、小写,以及去除两边的空白字符
String str2 = str1.toUpperCase();
System.out.println("str2 = " + str2); // YOU MAY BE OUT OF MY SIGHT, BUT NEVER OUT OF MY MIND.
System.out.println("str1 = " + str1); // You may be out of my sight, but never out of my mind.
String str3 = str1.toLowerCase();
System.out.println("str3 = " + str3); // you may be out of my sight, but never out of my mind.
System.out.println("str1 = " + str1); // You may be out of my sight, but never out of my mind.
String str4 = str1.trim();
System.out.println("str4 = " + str4); // You may be out of my sight, but never out of my mind.
System.out.println("-------------------------------------------");
// 判断字符串是否以某个子串开头或结尾
boolean b2 = str1.startsWith("You"); // false
System.out.println("b2 = " + b2);
b2 = str1.startsWith("You", 9); // 从下标9开始是否以You开头,true
System.out.println("b2 = " + b2);
b2 = str1.endsWith("mind."); // false
System.out.println("b2 = " + b2);
b2 = str1.endsWith(" "); // true
System.out.println("b2 = " + b2);
}
}
输出:
str1 = You may be out of my sight, but never out of my mind.
-------------------------------------------
b1 = true
b1 = false
str2 = YOU MAY BE OUT OF MY SIGHT, BUT NEVER OUT OF MY MIND.
str1 = You may be out of my sight, but never out of my mind.
str3 = you may be out of my sight, but never out of my mind.
str1 = You may be out of my sight, but never out of my mind.
str4 = You may be out of my sight, but never out of my mind.
-------------------------------------------
b2 = false
b2 = true
b2 = false
b2 = true
(6)String类实现登录功能的模拟
案例题目:
提示用户从键盘输入用户名和密码信息,若输入“admin”和“123456”则提示“登录成功,欢迎使用”,否则提示“用户名或密码错误,您还有n次机会”,若用户输入三次后依然错误则提示“账户已冻结,请联系客服人员!”
实现模拟登录功能通过String类中重写Object类中的方法实现,即需要用到boolean equals(Object anObject)
、int hashCode()
和boolean equalsIgnoreCase(String anotherString)
方法,如下:
package com.stage1.module3;
import java.util.Scanner;
/**
* @author Corley
* @date 2021/7/22 9:28
* @description javase-com.stage1.module3
*/
public class StringLoginTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
for (int i = 3; i > 0; i--) {
// 1.提示用户输入用户名和密码信息并保存
System.out.println("请输入您的用户名和密码:");
String userName = sc.next();
String password = sc.next();
// 2.判断用户名和密码是否分别为admin和123456并给出提示
if ("admin".equalsIgnoreCase(userName) && "123456".equals(password)) {
System.out.println("登录成功,欢迎使用!");
break;
}
if (1 == i) {
System.out.println("对不起,账户已冻结,请联系客服人员!");
} else {
System.out.println("对不起,用户名或密码错误,请重新输入,您还有" + (i - 1) + "次机会!");
}
}
// 关闭Scanner对象
sc.close();
}
}
演示如下:
请输入您的用户名和密码:
admin 123
对不起,用户名或密码错误,请重新输入,您还有2次机会!
请输入您的用户名和密码:
admin 12345
对不起,用户名或密码错误,请重新输入,您还有1次机会!
请输入您的用户名和密码:
admin 123456
登录成功,欢迎使用!
其中,"admin".equalsIgnoreCase(userName)
和"123456".equals(password)
是为了防止变量为空时作为调用对象可能发生的空指针异常。
(7)String类实现字符和字符串的正向查找
字符和字符串的正向查找需要用到int indexOf()
方法,使用如下:
package com.stage1.module3;
/**
* @author Corley
* @date 2021/7/22 9:41
* @description javase-com.stage1.module3
*/
public class StringIndexTest {
public static void main(String[] args) {
// 1.构造String类型的对象
String str = new String("You're unique, nothing can replace you.");
System.out.println("str = " + str);
// 2.实现字符串中指定字符和字符串的查找
// 查找字符
int pos1 = str.indexOf('E'); // 未查找到,返回-1
System.out.println("pos1 = " + pos1);
pos1 = str.indexOf('e'); // 5
System.out.println("pos1 = " + pos1);
pos1 = str.indexOf('e', 6); // 从下标6开始查找字符e第一次出现的位置,12
System.out.println("pos1 = " + pos1);
System.out.println("-------------------------------------------");
// 查找字符串
int pos2 = str.indexOf("are"); // 查找字符串中第一个字符的下标,-1
System.out.println("pos2 = " + pos2);
pos2 = str.indexOf("re"); // 4
System.out.println("pos2 = " + pos2);
pos2 = str.indexOf("re", 10); // 27
System.out.println("pos2 = " + pos2);
System.out.println("-------------------------------------------");
// 通用代码,查询字符串中所有"re"出现的索引位置
// 方式一
int pos3 = str.indexOf("re");
while (-1 != pos3) {
System.out.println("pos3 = " + pos3);
pos3 = str.indexOf("re", pos3 + 1);
}
System.out.println("-------------------------------------------");
// 方式二
pos3 = 0;
while (-1 != (pos3 = str.indexOf("re", pos3))) {
System.out.println("pos3 = " + pos3);
pos3 += "re".length();
}
}
}
输出:
str = You're unique, nothing can replace you.
pos1 = -1
pos1 = 5
pos1 = 12
-------------------------------------------
pos2 = -1
pos2 = 4
pos2 = 27
-------------------------------------------
pos3 = 4
pos3 = 27
-------------------------------------------
pos3 = 4
pos3 = 27
可以看到,在实现查询字符串中所有"re"出现的索引位置的通用代码时,第二种方式更优雅。
(8)String类实现字符和字符串的反向查找
字符和字符串的反向查找即从右向左查找,需要使用到int lastIndexOf()
方法。
使用如下:
package com.stage1.module3;
/**
* @author Corley
* @date 2021/7/22 9:41
* @description javase-com.stage1.module3
*/
public class StringIndexTest {
public static void main(String[] args) {
// 1.构造String类型的对象
String str = new String("You're unique, nothing can replace you.");
System.out.println("str = " + str);
// 2.实现字符串中指定字符和字符串的查找
// 查找字符
int pos1 = str.indexOf('E'); // 未查找到,返回-1
System.out.println("pos1 = " + pos1);
pos1 = str.indexOf('e'); // 5
System.out.println("pos1 = " + pos1);
pos1 = str.indexOf('e', 6); // 从下标6开始查找字符e第一次出现的位置,12
System.out.println("pos1 = " + pos1);
System.out.println("-------------------------------------------");
// 查找字符串
int pos2 = str.indexOf("are"); // 查找字符串中第一个字符的下标,-1
System.out.println("pos2 = " + pos2);
pos2 = str.indexOf("re"); // 4
System.out.println("pos2 = " + pos2);
pos2 = str.indexOf("re", 10); // 27
System.out.println("pos2 = " + pos2);
System.out.println("-------------------------------------------");
// 通用代码,查询字符串中所有"re"出现的索引位置
// 方式一
int pos3 = str.indexOf("re");
while (-1 != pos3) {
System.out.println("pos3 = " + pos3);
pos3 = str.indexOf("re", pos3 + 1);
}
System.out.println("-------------------------------------------");
// 方式二
pos3 = 0;
while (-1 != (pos3 = str.indexOf("re", pos3))) {
System.out.println("pos3 = " + pos3);
pos3 += "re".length();
}
System.out.println("-------------------------------------------");
// 3.实现字符和字符串的反向查找
// 查找字符
int pos4 = str.lastIndexOf('e'); // 33
System.out.println("pos4 = " + pos4);
pos4 = str.lastIndexOf('e', 24); // 从下标为24的位置开始反向查找,12
System.out.println("pos4 = " + pos4);
System.out.println("-------------------------------------------");
// 查找字符串
int pos5 = str.lastIndexOf("re"); // 27
System.out.println("pos5 = " + pos5);
pos5 = str.lastIndexOf("re", 20); // 从下标为24的位置开始反向查找,4
System.out.println("pos5 = " + pos5);
pos5 = str.lastIndexOf("re", 3); // 从下标为3的位置开始反向查找,-1
System.out.println("pos5 = " + pos5);
}
}
输出:
str = You're unique, nothing can replace you.
pos1 = -1
pos1 = 5
pos1 = 12
-------------------------------------------
pos2 = -1
pos2 = 4
pos2 = 27
-------------------------------------------
pos3 = 4
pos3 = 27
-------------------------------------------
pos3 = 4
pos3 = 27
-------------------------------------------
pos4 = 33
pos4 = 12
-------------------------------------------
pos5 = 27
pos5 = 4
pos5 = -1
(9)String类中子字符串的获取
String类中获取子字符串使用String substring()
方法。
案例题目:
提示用户从键盘输入一个字符串和一个字符,输出该字符(不含)后面的所有子字符串。
实现如下:
package com.stage1.module3;
import java.util.Scanner;
/**
* @author Corley
* @date 2021/7/22 12:27
* @description javase-com.stage1.module3
*/
public class StringSubStringTest {
public static void main(String[] args) {
// 1.构造String类型的对象
String str1 = new String("Good is good, but better carries it.");
System.out.println("str1 = " + str1);
System.out.println("-------------------------------------");
// 2.获取字符串中的部分内容并打印
// 从当前字符串中下标14开始获取子字符串
String str2 = str1.substring(14);
System.out.println("str2 = " + str2);
// 从当前字符串下标8开始、到12(不包含12)
String str3 = str1.substring(8, 12);
System.out.println("str3 = " + str3);
System.out.println("-------------------------------------");
// 3.获取输入字符串中从输入字符其的字符串内容
System.out.println("请输入一个字符串:");
Scanner sc = new Scanner(System.in);
String str4 = sc.next();
System.out.println("请输入一个字符:");
String str5 = sc.next();
// 从str4中查找str5第一次出现的索引位置
int pos = str4.indexOf(str5);
System.out.println("pos = " + pos);
// 根据获取到的位置获取子字符串
String str6 = str4.substring(pos + 1);
System.out.println("获取到的子字符串是:" + str6);
}
}
输出:
str1 = Good is good, but better carries it.
-------------------------------------
str2 = but better carries it.
str3 = good
-------------------------------------
请输入一个字符串:
hello,corley
请输入一个字符:
c
pos = 6
获取到的子字符串是:orley
3.正则表达式的概念和使用
(1)正则表达式的概念和规则
正则表达式本质是一个规则字符串 ,可以用于对字符串数据的格式进行验证 ,以及进行匹配、查找、替换等操作。
该字符串通常使用^
运算符作为开头标志、$
运算符作为结尾标志,也可以省略。
常见的规则如下:
正则表达式 | 含义 |
---|---|
[abc] | 可以出现a、b、c中任意一个字符 |
[^abc] | 可以出现任何字符,除了a、b、c的任意字符 |
[a-z] | 可以出现a、b、c、……、z中的任意一个字符 |
[a-zA-Z0-9] | 可以出现az、AZ、0~9中任意一个字符 |
. | 任意一个字符(通常不包含换行符) |
\d | 任意一个数字字符,相当于[0-9] |
\D | 任意一个非数字字符 |
\s | 空白字符,相当于[\t\n\x0B\f\r] |
\S | 非空白字符 |
\w | 任意一个单词字符,相当于[a-zA-Z_0-9] |
\W | 任意一个非单词字符 |
X? | 表示X可以出现一次或一次也没有,也就是0 ~ 1次 |
X* | 表示X可以出现零次或多次,也就是0 ~ n次 |
X+ | 表示X可以出现一次或多次,也就是1 ~ n次 |
X{n} | 表示X可以出现恰好 n 次 |
X{n, } | 表示X可以出现至少 n 次,也就是≥n次 |
X{n, m} | 表示X可以出现至少 n 次,但是不超过 m 次,也就是≥n并且≤m次 |
其中,matches(String regex)
方法可以用于判断调用字符串对象是否与参数指定的正则表达式匹配。
(2)正则表达式的编程使用
案例题目:
使用正则表达式描述一下银行卡密码的规则:要求是由6位数字组成。
使用正则表达式描述一下QQ号码的规则:要求是由非0开头的5~15位数组成。
使用正则表达式描述一下手机号码的规则:要求是由1开头,第二位数是3、4、5、7、8中的一位,总共11位。
描述身份证号码的规则:总共18位,6位数字代表地区,4位数字代表年,2位数字代表月,2位数字代表日期, 3位数字代表个人,最后一位可能数字也可能是X。
如下:
package com.stage1.module3;
import java.util.Scanner;
/**
* @author Corley
* @date 2021/7/22 18:34
* @description javase-com.stage1.module3
*/
public class StringRETest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str;
// 1.定义描述规则的正则表达式字符串
// 银行卡密码的规则:由6位数字组成
String reg1 = "^\\d{6}$"; // "\\d{6}"、"^[0-9]$"
// QQ号码的规则:由非0开头的5~15位数组成
String reg2 = "[1-9]\\d{4,14}";
// 手机号码的规则:由1开头,第二位数是3、4、5、7、8、9中的一位,总共11位
String reg3 = "1[345789]\\d{9}";
// 身份证号码的规则:总共18位,6位数字代表地区,4位数字代表年,2位数字代表月,2位数字代表日期, 3位数字代表个人,最后一位可能数字也可能是X
String reg4 = "(\\d{6})(\\d{4})(\\d{2})(\\d{2})(\\d{3})([0-9|X])";
while (true) {
// 2.提示用户输入指定的内容
System.out.println("请输入您的银行卡密码:");
str = sc.next();
// 3.判断用户输入的内容是否匹配指定的规则
if (str.matches(reg1)) {
System.out.println("银行卡密码格式正确!");
break;
} else {
System.out.println("银行卡密码格式错误!");
}
}
System.out.println("-----------------------------------");
while (true) {
// 2.提示用户输入指定的内容
System.out.println("请输入您的QQ号码:");
str = sc.next();
// 3.判断用户输入的内容是否匹配指定的规则
if (str.matches(reg2)) {
System.out.println("QQ号码格式正确!");
break;
} else {
System.out.println("QQ号码格式错误!");
}
}
System.out.println("-----------------------------------");
while (true) {
// 2.提示用户输入指定的内容
System.out.println("请输入您的手机号码:");
str = sc.next();
// 3.判断用户输入的内容是否匹配指定的规则
if (str.matches(reg3)) {
System.out.println("手机号码格式正确!");
break;
} else {
System.out.println("手机号码格式错误!");
}
}
System.out.println("-----------------------------------");
while (true) {
// 2.提示用户输入指定的内容
System.out.println("请输入您的身份证号码:");
str = sc.next();
// 3.判断用户输入的内容是否匹配指定的规则
if (str.matches(reg4)) {
System.out.println("身份证号码格式正确!");
break;
} else {
System.out.println("身份证号码格式错误!");
}
}
}
}
输出:
请输入您的银行卡密码:
12345
银行卡密码格式错误!
请输入您的银行卡密码:
1234567
银行卡密码格式错误!
请输入您的银行卡密码:
12345a
银行卡密码格式错误!
请输入您的银行卡密码:
123456
银行卡密码格式正确!
-----------------------------------
请输入您的QQ号码:
012345
QQ号码格式错误!
请输入您的QQ号码:
123
QQ号码格式错误!
请输入您的QQ号码:
12345123451234512345
QQ号码格式错误!
请输入您的QQ号码:
12345
QQ号码格式正确!
-----------------------------------
请输入您的手机号码:
12311111111
手机号码格式错误!
请输入您的手机号码:
1231111111
手机号码格式错误!
请输入您的手机号码:
123111111111
手机号码格式错误!
请输入您的手机号码:
13111111111
手机号码格式正确!
-----------------------------------
请输入您的身份证号码:
12121220210722123a
身份证号码格式错误!
请输入您的身份证号码:
12121220210722123X
身份证号码格式正确!
其中,正则表达式只能对字符串内容的格式进行检查,无法对数据内容的正确性进行检查,内容的正确性检查一般需要查询后台的数据库。
(3)正则表达式相关方法的使用
正则表达式常用的方法如下:
方法名称 | 方法说明 |
---|---|
String[] split(String regex) | 参数regex为正则表达式,以regex所表示的字符串为分隔符,将字符串拆分成字符串数组 |
String replace(char oldChar, char newChar) | 使用参数newChar替换此字符串中出现的所有参数 |
oldChar String replaceFirst(String regex, String replacement) | 替换此字符串匹配给定的正则表达式的第一个子字符串 |
String replaceAll(String regex, String replacement) | 将字符串中匹配正则表达式regex的字符串替换成replacement |
现在对这些方法进行测试,如下:
package com.stage1.module3;
import java.util.Arrays;
/**
* @author Corley
* @date 2021/7/22 19:03
* @description javase-com.stage1.module3
*/
public class StringREMethodTest {
public static void main(String[] args) {
// 1.创建字符串对象
String str1 = "She sells sea shells on the seashore. 12345. The seashells 67890 she sells are seashells she is sure.";
System.out.println("str1 = " + str1);
System.out.println("---------------------------------------");
// 2.根据指定字符串切割字符串
String[] sArr = str1.split("s[eh]"); // 按照se或sh切割字符串
System.out.println(Arrays.toString(sArr));
System.out.println("---------------------------------------");
// 3.对字符串进行替换
String str2 = str1.replace("se", "ma"); // 将se替换为ma
System.out.println("str2 = " + str2);
String str3 = str1.replaceFirst("\\d+", "***"); // 将第一个出现的数字字符串替换为***
System.out.println("str3 = " + str3);
String str4 = str1.replaceAll("sh?e", "##"); // 将所有的she或se替换为##
System.out.println("str4 = " + str4);
}
}
输出:
str1 = She sells sea shells on the seashore. 12345. The seashells 67890 she sells are seashells she is sure.
---------------------------------------
[She , lls , a , ells on the , a, ore. 12345. The , a, ells 67890 , e , lls are , a, ells , e is sure.]
---------------------------------------
str2 = She malls maa shells on the maashore. 12345. The maashells 67890 she malls are maashells she is sure.
str3 = She sells sea shells on the seashore. ***. The seashells 67890 she sells are seashells she is sure.
str4 = She ##lls ##a ##lls on the ##ashore. 12345. The ##a##lls 67890 ## ##lls are ##a##lls ## is sure.
总结
字符串不仅仅在Java中,在所有语言中都是最常用的一个数据类型,可以用于描述字符串事物,再怎怎么评价其重要性都不为过。