转载于:http://c.biancheng.net/java/40/
一般程序需要处理大量文本数据,Java 语言的文本数据被保存为字符或字符串类型。关于字符及字符串的操作主要用到 String 类和 StringBuffer 类,如连接、修改、替换、比较和查找等。
字符串是 Java 程序中经常处理的对象之一,因此如果字符串运用得不好,将影响到程序的运行效率。本章从如何定义字符串开始介绍字符串本身的特性,以及各种字符串操作的实现方法。
字符串是 Java 中特殊的类,使用方法像一般的基本数据类型,被广泛应用在 Java 编程中。Java 没有内置的字符串类型,而是在标准 Java 类库中提供了一个 String 类来创建和操作字符串。
在 Java 中定义一个字符串最简单的方法是用双引号把它包围起来。这种用双引号括起来的一串字符实际上都是 String 对象,如字符串“Hello”在编译后即成为 String 对象。因此也可以通过创建 String 类的实例来定义字符串。
不论使用哪种形式创建字符串,字符串对象一旦被创建,其值是不能改变的,但可以使用其他变量重新赋值的方式进行更改。
注意:由于类和对象的的内容在第八章才会讲解,所以只要遇到类和对象的概念,知道如何操作就可以了,不需要明白为什么要这样使用。
直接定义字符串是指使用双引号表示字符串中的内容,例如“Hello Java”、“Java 编程”等。具体方法是用字符串常量直接初始化一个 String 对象,示例如下:
String str = "Hello Java";
或者
String str;
str = "Hello Java";
注意:字符串变量必须经过初始化才能使用。
下面的实例演示了直接创建字符串的几种用法。
String str = "我是一只小小鸟"; // 结果:我是一只小小鸟
String word;
word = "I am a bird"; // 结果:I am a bird
word = "to fly
"; // 结果:to fly
word = "Let\'s say that it\'s true"; // 结果:Let's say that it's true
System.out.println(word);
word = "北京\\上海\\广州"; // 结果:北京\上海\广州
前面我们提到在 Java 中每个双引号定义的字符串都是一个 String 类的对象。因此,可以通过使用 String 类的构造方法来创建字符串,该类位于 java.lang 包中(关于 Java 常用的包,教程后面会详细讲解)。
String 类的构造方法有多种重载形式,每种形式都可以定义字符串。下面介绍最常用的几种形式。
注意:具有和类名相同的名称,而且没有返回类型的方法称为构造方法。重载是指在一个类中定义多个同名的方法,但要求每个方法具有不同的参数的类型或参数的个数。教程后面会详细讲解,这里了解一下就可以。
初始化一个新创建的 String 对象,表示一个空字符序列。
初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列。换句话说,新创建的字符串是该参数字符串的副本。例如:
String str1 = new String("Hello Java");
String str2 = new String(str1);
这里 str1 和 str2 的值是相等的。
分配一个新的字符串,将参数中的字符数组元素全部变为字符串。该字符数组的内容已被复制,后续对字符数组的修改不会影响新创建的字符串。例如:
char a[] = {'H','e','l','l','0'};
String sChar = new String(a);
a[1] = 's';
上述 sChar 变量的值是字符串“Hello”。 即使在创建字符串之后,对 a 数组中的第 2 个元素进行了修改,但未影响 sChar 的值。
注意:如果你不知道数组是什么,可先阅读《Java数组简介》一节对数组大概了解之后再继续学习本节内容。
分配一个新的 String,它包含来自该字符数组参数一个子数组的字符。offset 参数是子数组第一个字符的索引,count 参数指定子数组的长度。该子数组的内容已被赋值,后续对字符数组的修改不会影响新创建的字符串。例如:
char a[]={'H','e','l','l','o'};
String sChar=new String(a,1,4);
a[1]='s';
上述 sChar 变量的值是字符串“ello”。该构造方法使用字符数组中的部分连续元素来创建字符串对象。offset 参数指定起始索引值,count 指定截取元素的个数。创建字符串对象后,即使在后面修改了 a 数组中第 2 个元素的值,对 sChar 的值也没有任何影响。
正如前面所看到的,String 类包含许多方法。 而且, 在标准库中有几千个类, 方法数量更加惊人。要想记住所有的类和方法是一件不太不可能的事情。 因此,学会使用在线 API 文档十分重要,从中可以查阅到标准类库中的所有类和方法。
对于 Java 而言,API 文档详细说明了 Java 中常用类和方法的功能,开发者可以通过查阅 API 文档,调用应用程序接口(API)来编程。
Java 中很多类,每一个类又有很多方法和变量,通过查看 Java API 文档能够知道这些类、方法和变量如何使用。Java 官方为 Java SE 提供了基于 HTML 的 API 文档。作为 Java 程序员应该熟悉如何使用 API 文档。
本节介绍一下如何使用 Java SE 的 API 文档。Java 官方提供了 Java 8 在线 API 文档,网址是 http://docs.oracle.com/javase/8/docs/api/,页面如图 1 所示。
提示:很多读者希望能够有离线的中文 Java API 文档,但 Java 官方只提供了 Java 6 的中文 API 文档,该文件下载地址是 http://download.oracle.com/technetwork/java/javase/6/docs/zh/api.zip,下载完成后解压 api.zip 文件,找到其中的 index.html 文件,双击就会在浏览器中打开 API 文档了。
下面介绍一下如何使用 API 文档,熟悉一下 API 文档页面中的各个部分含义,如图 2 所示,类和接口中,斜文字体显示是接口,正常字体才是类。
在类窗口还有很多内容,向下拖曳滚动条会看到如图 3 所示页面,其中“字段摘要”描述了类中的实例变量和静态变量,“构造方法摘要”描述了类中所有构造方法,“方法摘要”描述了类中所有方法。这些“摘要”只是一个概要说明,单击链接可以进入到该主题更加详细的描述,如图 4 所示单击了 compareTo 方法看到的详细信息。
查询 API 的一般流程是:找包→找类或接口→查看类或接口→找方法或变量。读者可以尝试查找一下 String、StringBuffer 和 StringBuilder 这些字符串类的 API 文档,熟悉一下这些类的用法。
String 在编程中被广泛使用,所以掌握 String 和 int 的相互转换方法是极其重要的。本节前面部分主要讲解了 String 转换 int 和 int 转换 String 方法,并提供了示例代码,后面部分对 valueOf()、parse() 和 toString() 等具体方法进行介绍。
String 字符串转整型 int 有以下两种方式:
注意:Integer 是一个类,是 int 基本数据类型的封装类。在《Java Integer类》一节中我们会详细讲解。
例如下面代码所示:
public static void main(String[] args) {
String str = "123";
int n = 0;
// 第一种转换方法:Integer.parseInt(str)
n = Integer.parseInt(str);
System.out.println("Integer.parseInt(str) : " + n);
// 第二种转换方法:Integer.valueOf(str).intValue()
n = 0;
n = Integer.valueOf(str).intValue();
System.out.println("Integer.parseInt(str) : " + n);
}
输出结果为:
Integer.parseInt(str) : 123
Integer.parseInt(str) : 123
在 String 转换 int 时,String 的值一定是整数,否则会报数字转换异常(java.lang.NumberFormatException)。
整型 int 转 String 字符串类型有以下 3 种方法:
例如下面代码所示:
public static void main(String[] args) {
int num = 10;
// 第一种方法:String.valueOf(i);
num = 10;
String str = String.valueOf(num);
System.out.println("str:" + str);
// 第二种方法:Integer.toString(i);
num = 10;
String str2 = Integer.toString(num);
System.out.println("str2:" + str2);
// 第三种方法:"" + i;
String str3 = num + "";
System.out.println("str3:" + str3);
}
输出结果为:
str:10
str2:10
str3:10
使用第三种方法相对第一第二种耗时比较大。在使用第一种 valueOf() 方法时,注意 valueOf 括号中的值不能为空,否则会报空指针异常(NullPointerException)。
valueOf() 方法将数据的内部格式转换为可读的形式。它是一种静态方法,对于所有 Java 内置的类型,在字符串内被重载,以便每一种类型都能被转换成字符串。valueOf() 方法还被类型 Object 重载,所以创建的任何形式类的对象也可被用作一个参数。这里是它的几种形式:
static String valueOf(double num)
static String valueOf(long num)
static String valueOf(Object ob)
static String valueOf(char chars[])
与前面的讨论一样,调用 valueOf() 方法可以得到其他类型数据的字符串形式——例如在进行连接操作时。对各种数据类型,可以直接调用这种方法得到合理的字符串形式。所有的简单类型数据转换成相应于它们的普通字符串形式。任何传递给 valueOf() 方法的对象都将返回对象的 toString() 方法调用的结果。事实上,也可以通过直接调用 toString() 方法而得到相同的结果。
对大多数数组,valueOf() 方法返回一个相当晦涩的字符串,这说明它是一个某种类型的数组。然而对于字符数组,它创建一个包含了字符数组中的字符的字符串对象。valueOf() 方法有一种特定形式允许指定字符数组的一个子集。
它具有如下的一般形式:
static String valueOf(char chars[ ], int startIndex, int numChars)
这里 chars 是存放字符的数组,startIndex 是字符数组中期望得到的子字符串的首字符下标,numChars 指定子字符串的长度。
parseXxx(String) 这种形式,是指把字符串转换为数值型,其中 Xxx 对应不同的数据类型,然后转换为 Xxx 指定的类型,如 int 型和 float 型。
toString() 可以把一个引用类型转换为 String 字符串类型,是 sun 公司开发 Java 的时候为了方便所有类的字符串操作而特意加入的一个方法。
对于已经定义的字符串,可以对其进行各种操作。连接多个字符串是字符串操作中最简单的一种。通过字符串连接,可以将两个或多个字符串、字符、整数和浮点数等类型的数据连成一个更大的字符串。
String 字符串虽然是不可变字符串,但也可以进行拼接只是会产生一个新的对象。String 字符串拼接可以使用“+”运算符或 String 的 concat(String str) 方法。“+”运算符优势是可以连接任何类型数据拼接成为字符串,而 concat 方法只能拼接 String 类型字符串。
与绝大多数的程序设计语言一样,Java 语言允许使用“+”号连接(拼接)两个字符串。“+”运算符是最简单、最快捷,也是使用最多的字符串连接方式。在使用“+”运算符连接字符串和 int 型(或 double 型)数据时,“+”将 int(或 double)型数据自动转换成 String 类型。
下面的实例使用“+”运算符连接了 3 个数组和 1 个字符串。
public static void main(String[] args) {
int[] no = new int[] { 501, 101, 204, 102, 334 }; // 定义学号数组
String[] names = new String[] { "张城", "刘丽丽", "李国旺", "孟红霞", "贺宁" }; // 定义姓名数组
String[] classes = new String[] { "数学", "语文", "数学", "英语", "英语" }; // 定义课程数组
System.out.println("本次考试学生信息如下:");
// 循环遍历数组,连接字符串
for (int i = 0; i < no.length; i++) {
System.out.println("学号:" + no[i] + "|姓名:" + names[i] + "|课程:" + classes[i] + "|班级:" + "初二(三)班");
}
}
上述代码首先创建了 3 个包含有 5 个元素的数组,然后循环遍历数组,遍历的次数为 5。在循环体内输出学号、姓名和课程,并使用“+”运算符连接班级最终形成一个字符串。程序运行后输出结果如下:
本次考试学生信息如下:
学号:501|姓名:张城|课程:数学|班级:初二(三)班
学号:101|姓名:刘丽丽|课程:语文丨班级:初二(三)班
学号:204|姓名:李国旺|课程:数学|班级:初二(三)班
学号:102|姓名:孟红霞|课程:英语|班级:初二(三)班
学号:334|姓名:贺宁|课程:英语|班级;初二(三)班
当定义的字符串值的长度过长时,可以分作多行来写,这样比较容易阅读。例如:
String str="Welcome to"+"Beijing"
+"欢迎来到"+"北京。"
+"北京我的故乡。";
在 Java 中,String 类的 concat() 方法实现了将一个字符串连接到另一个字符串的后面。concat() 方法语法格式如下:
字符串 1.concat(字符串 2);
执行结果是字符串 2 被连接到字符串 1 后面,形成新的字符串。
如 concat() 方法的语法所示,concat() 方法一次只能连接两个字符串,如果需要连接多个字符串,需要调用多次 concat() 方法。
下面创建一个实例代码来演示如何使用 concat() 方法连接多个字符串。
public static void main(String[] args) {
String info = "三国演义、";
info = info.concat("西游记、");
info = info.concat("水浒传、");
info = info.concat("红楼梦");
System.out.println(info);
String cn = "中国";
System.out.println(cn.concat("北京").concat("海淀区").concat("人民公园"));
}
执行该段代码,输出的结果如下所示。
三国演义、西游记、水浒传、红楼梦
中国北京海淀区人民公园
前面介绍的例子都是字符串与字符串进行连接,其实字符串也可同其他基本数据类型进行连接。如果将字符串同这些数据类型数据进行连接,此时会将这些数据直接转换成字符串。
编写一个 Java 程序,实现将字符串与整型、浮点型变量相连并输出结果。实现代码如下:
public static void main(String[] args) {
String book = "三国演义"; // 字符串
int price = 59; // 整型变量
float readtime = 2.5f; // 浮点型变量
System.out.println("我买了一本图书,名字是:" + book + "\n价格是:" + price + "\n我每天阅读" + readtime + "小时");
}
上述代码实现的是将字符串变量 book 与整型变量 price 和浮点型变量 readtime 相连后将结果输出。在这里定义的 price 和 readtime 都不是字符串,当它们与字符串相连时会自动调用自身的 toString() 方法将其转换成字符串形式,然后再参与连接运算。因此,程序运行后的结果如下所示:
我买了一本图书,名字是:三国演义
价格是:59
我每天阅读2.5小时
假设将本例中的输出语句修改为如下形式:
System.out.println("我买了一本图书,名字是:"+book+"\n 价格是:"+price+"\n我每天阅读"+(price+readtime)+"小时");
因为运算符具有优先级,而圆括号的优先级最高,所以先计算 price 与 readtime 的和,再将结果转换成字符串进行连接。此时的运行结果如下所示:
我买了一本图书,名字是:三国演义
价格是:59
我每天阅读61.5小时
注意:只要“+”运算符的一个操作数是字符串,编译器就会将另一个操作数转换成字符串形式,所以应该谨慎地将其他数据类型与字符串相连,以免出现意想不到的结果。
在 Java 中,要获取字符串的长度,可以使用 String 类的 length() 方法,其语法形式如下:
字符串名.length();
在学生信息管理系统中对管理员密码有这样的规定,即密码长度必须大于 6 位且小于 12 位。因为密码太短容易被破解,太长的话又不容易记住。这就需要首先获取用户输入的密码字符串,然后调用 length() 方法获取长度,再做进一步的长度判断,最终实现代码如下所示:
public static void main(String[] args) {
String sys = "学生信息管理";// 字义一个字符串表示系统名称
System.out.println("欢迎进入《" + sys + "》系统");// 输出系统名称
System.out.println("请设置一个管理员密码:");
Scanner input = new Scanner(System.in);
String pass = input.next();// 获取用户输入的密码
int length = pass.length();// 获取密码的长度
if (length > 6 && length < 12) {
System.out.println("密码长度符合规定。");
System.out.println("已生效,请牢记密码:" + pass);
} else if (length >= 12) {
System.out.println("密码过长。");
} else {
System.out.println("密码过短。");
}
}
上述代码将用户输入的密码保存到字符串变量 pass 中,再调用 pass.length() 方法将长度保存到 length 变量,然后使用 if 语句根据长度给出提示。
运行程序,当输入的密码过短时,运行结果如下所示:
欢迎进入《学生信息管理》系统
请设置一个管理员密码:
123456
密码过短。
当输入的密码符合规定时,运行结果如下所示:
欢迎进入《学生信息管理》系统
请设置一个管理员密码:
abc12345678
密码长度符合规定。
已生效,请牢记密码:abc12345678
String 类的 toLowerCase() 方法可以将字符串中的所有字符全部转换成小写,而非字母的字符不受影响。语法格式如下:
字符串名.toLowerCase() // 将字符串中的字母全部转换为小写,非字母不受影响
toUpperCase() 则将字符串中的所有字符全部转换成大写,而非字母的字符不受影响。语法格式如下:
字符串名.toUpperCase() // 将字符串中的字母全部转换为大写,非字母不受影响
例如:
String str="abcdef 我 ghijklmn";
System.out.println(str.toLowerCase()); // 输出:abcdef 我 ghijklmn
System.out.println(str.toUpperCase()); // 输出:ABCDEF 我 GHIJKLMN
下面的实例代码演示了如何对字符串应用大写和小写转换。
public static void main(String[] args) {
String en = "The Day You Went Away"; // 定义原始字符串
System.out.println("原始字符串:"+en);
System.out.println("使用 toLowerCase() 方法之后为:"+en.toLowerCase());
System.out.println("使用 toUpperCase() 方法之后为:"+en.toUpperCase());
en = "sun sun 是太阳,圆圆挂在 SKY 上"; // 定义原始字符串
System.out.println("原始字符串:"+en);
System.out.println("使用 toLowerCase() 方法之后为:"+en.toLowerCase());
System.out.println("使用 toUpperCase() 方法之后为:"+en.toUpperCase());
en = "select id,name,sex,address,birthday from students";
System.out.println("原始字符串:"+en); // 定义原始字符串
System.out.println("使用 toLowerCase() 方法之后为:"+en.toLowerCase());
System.out.println("使用 toUpperCase() 方法之后为:"+en.toUpperCase());
}
代码比较简单,运行后的输出结果如下:
原始字符串:The Day You Went Away
使用 toLowerCase() 方法之后为:the day you went away
使用 toUpperCase() 方法之后为:THE DAY YOU WENT AWAY
原始字符串:sun sun 是太阳,圆圆挂在 SKY 上
使用 toLowerCase() 方法之后为:sun sun 是太阳,圆圆挂在 sky 上
使用 toUpperCase() 方法之后为:SUN SUN 是太阳,圆圆挂在 SKY 上
原始字符串:select id,name,sex,address,birthday from students
使用 toLowerCase() 方法之后为:select id,name,sex,address,birthday from students
使用 toUpperCase() 方法之后为:SELECT ID,NAME,SEX,ADDRESS,BIRTHDAY FROM STUDENTS
字符串中存在的首尾空格一般情况下都没有任何意义,如字符串“ Hello ”,但是这些空格会影响到字符串的操作,如连接字符串或比较字符串等,所以应该去掉字符串中的首尾空格,这需要使用 String 类提供的 trim() 方法。
trim() 方法的语法形式如下:
字符串名.trim()
使用 trim() 方法的示例如下:
String str = " hello ";
System.out.println(str.length()); // 输出 7
System.out.println(str.trim().length()); // 输出 5
从该示例中可以看出,字符串中的每个空格占一个位置,直接影响了计算字符串的长度。
如果不确定要操作的字符串首尾是否有空格,最好在操作之前调用该字符串的 trim() 方法去除首尾空格,然后再对其进行操作。
注意:trim() 只能去掉字符串中前后的半角空格(英文空格),而无法去掉全角空格(中文空格)。可用以下代码将全角空格替换为半角空格再进行操作,其中替换是 String 类的 replace() 方法,《Java字符串的替换》一节会详细介绍这个方法。
str = str.replace((char) 12288, ' '); // 将中文空格替换为英文空格
str = str.trim();
其中,12288 是中文全角空格的 unicode 编码。
在 String 中提供了两个截取字符串的方法,一个是从指定位置截取到字符串结尾,另一个是截取指定范围的内容。下面对这两种方法分别进行介绍。
此方式用于提取从索引位置开始至结尾处的字符串部分。调用时,括号中是需要提取字符串的开始位置,方法的返回值是提取的字符串。例如:
String str = "我爱 Java 编程";
String result = str.substring(3);
System.out.println(result); // 输出:Java 编程
此方法中的 beginIndex 表示截取的起始索引,截取的字符串中包括起始索引对应的字符;endIndex 表示结束索引,截取的字符串中不包括结束索引对应的字符,如果不指定 endIndex,则表示截取到目标字符串末尾。该方法用于提取位置 beginIndex 和位置 endIndex 位置之间的字符串部分。
这里需要特别注意的是, 对于开始位置 beginIndex, Java 是基于字符串的首字符索引为 0 处理的,但是对于结束位置 endIndex,Java 是基于字符串的首字符索引为 1 来处理的,如图 1 所示。
注意:substring() 方法是按字符截取,而不是按字节截取。
创建一个字符串,对它使用 substring() 方法进行截取并输出结果。示例代码如下:
public static void main(String[] args) {
String day = "Today is Monday"; //原始字符串
System.out.println("substring(0)结果:"+day.substring(0));
System.out.println("substring(2)结果:"+day.substring(2));
System.out.println("substring(10)结果:"+day.substring(10));
System.out.println("substring(2,10)结果:"+day.substring(2,10));
System.out.println("substring(0,5)结果:"+day.substring(0,5));
}
输出结果如下所示:
substring(0)结果:Today is Monday
substring(2)结果:day is Monday
substring(10)结果:onday
substring(2,10)结果:day is M
substring(0,5)结果:Today
String 类的 split() 方法可以按指定的分割符对目标字符串进行分割,分割后的内容存放在字符串数组中。该方法主要有如下两种重载形式:
str.split(String sign)
str.split(String sign,int limit)
其中它们的含义如下:
使用分隔符注意如下:
1)“.”和“|”都是转义字符,必须得加“\”。
String.split("\\.")
,这样才能正确的分隔开,不能用String.split(".")
。String.split("\\|")
,这样才能正确的分隔开,不能用String.split("|")
。2)如果在一个字符串中有多个分隔符,可以用“|”作为连字符,比如:“acount=? and uu =? or n=?”,把三个都分隔出来,可以用String.split("and|or")
。
使用 split() 方法对字符串进行分割的实例如下:
public static void main(String[] args) {
String Colors = "Red,Black,White,Yellow,Blue";
String[] arr1 = Colors.split(","); // 不限制元素个数
String[] arr2 = Colors.split(",", 3); // 限制元素个数为3
System.out.println("所有颜色为:");
for (int i = 0; i < arr1.length; i++) {
System.out.println(arr1[i]);
}
System.out.println("前三个颜色为:");
for (int j = 0; j < arr2.length; j++) {
System.out.println(arr2[j]);
}
}
输出结果如下:
所有颜色为:
Red
Black
White
Yellow Blue
前三个颜色为:
Red
Black
White,Yellow,Blue
从输出的结果可以看出,当指定分割字符串后组成的数组长度(大于或等于 1)时,数组的前几个元素为字符串分割后的前几个字符,而最后一个元素为字符串的剩余部分。
例如,在该实例中,指定了 arr2 的长度为 3,而字符串 Colors 分割后组成的数组长度为 5。因此会将 arr2 中的前两个元素赋值为 Colors 分割后的前两个字符,arr2 中的第 3 个元素为 Colors 字符串的后 3 个字符组成的字符串。
在新闻网站中通常以列表的形式显示最新新闻的动态标题。一般情况下,一行显示一条新闻标题,而新闻标题往往比较长,因此需要对它进行截取,将超出部分显示成一个省略号“…”。
下面编写 Java 代码,实现使用字符串的 substring() 方法来截取新闻标题并以列表的形式显示的功能。代码如下:
public static void main(String[] args) {
// 定义存储新闻标题的数组
String[] news = new String[] { "如何快速掌握Java", "听老王剖析Java中的运算符", "学习Java的十大忠告", "你所不知道的java网络编程技巧大全", "Java面试题大全" };
String title = "************* 新闻列表 *************";
System.out.println(title.substring(10, 30));
System.out.println("----------------------------------------------");
/*
* 循环遍历数组截取数组元素中的前10个字符作为列表展示
*/
for (int i = 0; i < news.length; i++) {
// 判断数组元素的长度是否大于10,如果大于,则截取,否则全部显示
if (news[i].length() > 10) {
System.out.println(news[i].substring(0, 10) + "…");
} else {
System.out.println(news[i]);
}
}
}
运行该程序,输出的结果如下所示。
************* 新闻列表 *************
如何快速掌握Java
听老王剖析java中…
学习Java的十大忠…
你所不知道的java…
Java面试题大全
在该程序中,首先定义了存储新闻标题的数组,元素类型为 String 类型,然后循环遍历该数组,在循环体中,判断数组中的元素长度是否大于 10,如果大于,则使用 String 类的 substring() 方法截取前 10 个字符并输出,否则将数组中的元素输出即可。
因为要截取的是新闻标题中的前 10 个字符,因此,起始位置从 0 开始,结束位置为 10(索引从 1 开始),即使用 substring(0,10) 就完成了新闻标题的截取操作。
在 Java 中,String 类提供了 3 种字符串替换方法,分别是 replace()、replaceFirst() 和 replaceAll(),本文将详细介绍它们的使用方法。
replace() 方法用于将目标字符串中的指定字符(串)替换成新的字符(串),其语法格式如下:
字符串.replace(String oldChar, String newChar)
其中,oldChar 表示被替换的字符串;newChar 表示用于替换的字符串。replace() 方法会将字符串中所有 oldChar 替换成 newChar。
创建一个字符串,对它使用 replace() 方法进行字符串替换并输出结果。代码如下:
public static void main(String[] args) {
String words = "hello java,hello php";
System.out.println("原始字符串是'"+words+"'");
System.out.println("replace(\"l\",\"D\")结果:"+words.replace("l","D"));
System.out.println("replace(\"hello\",\"你好\")结果:"+words.replace("hello","你好 "));
words = "hr's dog";
System.out.println("原始字符串是'"+words+"'");
System.out.println("replace(\"r's\",\"is\")结果:"+words.replace("r's","is"));
}
输出结果如下所示:
原始字符串是'hello java,hello php'
replace("l","D")结果:heDDo java,heDDo php
replace("hello","你好")结果:你好 java,你好 php
原始字符串是'hr's dog'
replace("r's","is")结果:his dog
replaceFirst() 方法用于将目标字符串中匹配某正则表达式的第一个子字符串替换成新的字符串,其语法形式如下:
字符串.replaceFirst(String regex, String replacement)
其中,regex 表示正则表达式;replacement 表示用于替换的字符串。例如:
String words = "hello java,hello php";
String newStr = words.replaceFirst("hello","你好 ");
System.out.println(newStr); // 输出:你好 java,hello php
replaceAll() 方法用于将目标字符串中匹配某正则表达式的所有子字符串替换成新的字符串,其语法形式如下:
字符串.replaceAll(String regex, String replacement)
其中,regex 表示正则表达式,replacement 表示用于替换的字符串。例如:
String words = "hello java,hello php";
String newStr = words.replaceAll("hello","你好 ");
System.out.println(newStr); // 输出:你好 java,你好 php
注意:关于正则表达式的内容会在本章的最后几节讲解,在这里了解如何操作就可以了。
可直接点击《Java字符串替换实例》一节进行巩固练习。
假设有一段文本里面有很多错误,如错别字。现在使用 Java 中的字符串替换方法对它进行批量修改和纠正,其中就用到了我们在《Java字符串的替换》一节中学到的 String 类的 replace() 方法、replaceFirst() 方法和 replaceAll() 方法。
创建一个 Java 类,然后在主方法 main() 中编写代码,具体代码如下所示。
public static void main(String[] args) {
// 定义原始字符串
String intro = "今天时星其天,外面时下雨天。妈米去买菜了,漏网在家写作业。" + "语文作业时”其”写 5 行,数学使第 10 页。";
// 将文本中的所有"时"和"使"都替换为"是"
String newStrFirst = intro.replaceAll("[时使]", "是");
// 将文本中的所有"妈米"改为"妈妈"
String newStrSecond = newStrFirst.replaceAll("妈米", "妈妈");
// 将文本中的所有"漏网"改为"留我"
String newStrThird = newStrSecond.replaceAll("漏网", "留我");
// 将文本中第一次出现的"其"改为"期"
String newStrFourth = newStrThird.replaceFirst("[其]", "期");
// 输出最终字符串
System.out.println(newStrFourth);
}
运行该程序,输出的正确字符串内容如下:
今天是星期天,外面是下雨天。妈妈去买菜了,留我在家写作业。语文作业是”其”写 5 行,数学是第 10 页。
字符串比较是常见的操作,包括比较相等、比较大小、比较前缀和后缀串等。在 Java 中,比较字符串的常用方法有 3 个:equals() 方法、equalsIgnoreCase() 方法、 compareTo() 方法。下面详细介绍这 3 个方法的使用。
equals() 方法将逐个地比较两个字符串的每个字符是否相同。如果两个字符串具有相同的字符和长度,它返回 true,否则返回 false。对于字符的大小写,也在检查的范围之内。equals() 方法的语法格式如下:
str1.equals(str2);
str1 和 str2 可以是字符串变量, 也可以是字符串字面量。 例如, 下列表达式是合法的:
"Hello".equals(greeting)
下面的代码说明了 equals() 方法的使用:
String str1 = "abc";
String str2 = new String("abc");
String str3 = "ABC";
System.out.println(str1.equals(str2)); // 输出 true
System.out.println(str1.equals(str3)); // 输出 false
在第一次进入系统时要求管理员设置一个密码,出于安全考虑密码需要输入两次,如果两次输入的密码一致才生效,否则提示失败。具体实现代码如下:
public static void main(String[] args) {
String sys = "学生信息管理";
System.out.println("欢迎进入《" + sys + "》系统");
System.out.println("请设置一个管理员密码:");
Scanner input = new Scanner(System.in);
String pass = input.next(); // 设置密码
System.out.println("重复管理员密码:");
input = new Scanner(System.in);
String pass1 = input.next(); // 确认密码
if (pass.equals(pass1)) { // 比较两个密码
System.out.println("已生效,请牢记密码:" + pass);
} else {
System.out.println("两次密码不一致,请重新设置。");
}
}
运行该程序,由于 equals() 方法区分大小写,所以当两次输入的密码完全一致时,equals() 方法返回 true,输出结果如下所示:
欢迎进入《学生信息管理》系统
请设置一个管理员密码:
abcdef
重复管理员密码:
abcdef
已生效,请牢记密码:abcdef
否则输出如图下所示的结果:
欢迎进入《学生信息管理》系统
请设置一个管理员密码:
abcdef
重复管理员密码:
aBcdef
两次密码不一致,请重新设置。
equalsIgnoreCase() 方法的作用和语法与 equals() 方法完全相同,唯一不同的是 equalsIgnoreCase() 比较时不区分大小写。当比较两个字符串时,它会认为 A-Z 和 a-z 是一样的。
下面的代码说明了 equalsIgnoreCase() 的使用:
String str1 = "abc";
String str2 = "ABC";
System.out.println(str1.equalsIgnoreCase(str2)); // 输出 true
在会员系统中需要输入用户名和密码进行检验,下面使用 equalsIgnoreCase() 方法实现检验登录时不区分用户名和密码的大小写,具体的代码实现如下所示。
public static void main(String[] args) {
String sys = "学生信息管理";
System.out.println("欢迎进入《" + sys + "》系统");
System.out.println("请输入管理员名称:");
Scanner input = new Scanner(System.in);
String name = input.next(); // 获取用户输入的名称
System.out.println("请输入管理员密码:");
input = new Scanner(System.in);
String pass = input.next(); // 获取用户输入的密码
// 比较用户名与密码,注意此处忽略大小写
if (name.equalsIgnoreCase("admin") && pass.equalsIgnoreCase("somboy")) { // 验证
System.out.println("登录成功。");
} else {
System.out.println("登录失败。");
}
}
在上述代码中,由于使用 equalsIgnoreCase() 方法进行比较,所以会忽略大小写判断。因此输入 ADMIN 和 SOMBOY 也会验证通过,如下所示:
欢迎进入《学生信息管理》系统
请输入管理员名称:
ADMIN
请输入管理员密码:
SOMBOY
登录成功。
否则输出结果如下所示:
欢迎进入《学生信息管理》系统
请输入管理员名称:
admin
请输入管理员密码:
sommboy
登录失败。
理解 equals() 方法和==
运算符执行的是两个不同的操作是重要的。如同刚才解释的那样,equals() 方法比较字符串对象中的字符。而==
运算符比较两个对象引用看它们是否引用相同的实例。
下面的程序说明了两个不同的字符串(String)对象是如何能够包含相同字符的,但同时这些对象引用是不相等的:
String s1 = "Hello";
String s2 = new String(s1);
System.out.println(s1.equals(s2)); // 输出true
System.out.println(s1 == s2); // 输出false
变量 s1 指向由“Hello”创建的字符串实例。s2 所指的的对象是以 s1 作为初始化而创建的。因此这两个字符串对象的内容是一样的。但它们是不同的对象,这就意味着 s1 和 s2 没有指向同一的对象,因此它们是不==
的。
因此,千万不要使用==
运算符测试字符串的相等性,以免在程序中出现糟糕的 bug。从表面上看,这种 bug 很像随机产生的间歇性错误。
对于习惯使用 C++ 的 String 类的人来说,在进行相等性检测的时候一定要特别小心。C++ 的 String 类重载了==
运算符以便检测字符串内容的相等性。可惜 Java 没有采用这种方式,它的字符串“看起来、感觉起来”与数值一样,但进行相等性测试时,其操作方式又类似于指针。语言的设计者本应该像对 C++ 那样也进行特殊处理, 即重定义==
运算符。
当然,每一种语言都会存在一些不太一致的地方。C 程序员从不使用==
对字符串进行比较,而使用 strcmp 函数。Java 的 compareTo 方法与 strcmp 完全类似。所以下面我们来介绍 Java 的 compareTo 方法。
通常,仅仅知道两个字符串是否相同是不够的。对于排序应用来说,必须知道一个字符串是大于、等于还是小于另一个。一个字符串小于另一个指的是它在字典中先出现。而一个字符串大于另一个指的是它在字典中后出现。字符串(String)的 compareTo() 方法实现了这种功能。
compareTo() 方法用于按字典顺序比较两个字符串的大小,该比较是基于字符串各个字符的 Unicode 值。compareTo() 方法的语法格式如下:
str.compareTo(String otherstr);
它会按字典顺序将 str 表示的字符序列与 otherstr 参数表示的字符序列进行比较。如果按字典顺序 str 位于 otherster 参数之前,比较结果为一个负整数;如果 str 位于 otherstr 之后,比较结果为一个正整数;如果两个字符串相等,则结果为 0。
提示:如果两个字符串调用 equals() 方法返回 true,那么调用 compareTo() 方法会返回 0。
编写一个简单的 Java 程序,演示 compareTo() 方法比较字符串的用法,以及返回值的区别。代码如下:
public static void main(String[] args) {
String str = "A";
String str1 = "a";
System.out.println("str=" + str);
System.out.println("str1=" + str1);
System.out.println("str.compareTo(str1)的结果是:" + str.compareTo(str1));
System.out.println("str1.compareTo(str)的结果是:" + str1.compareTo(str));
System.out.println("str1.compareTo('a')的结果是:" + str1.compareTo("a"));
}
上述代码定义了两个字符串“A”和“a”,然后调用 compareTo() 方法进行相互比较。最后一行代码拿“a”与“a”进行比较,由于两个字符串相同比较结果为 0。运行后的输出结果如下:
str = A
str1 = a
str.compareTo(str1)的结果是:-32
str1.compareTo(str)的结果是:32
str1.compareTo('a')的结果是:0
“”是一个长度为 0 且占内存的空字符串,在内存中分配一个空间,可以使用 Object 对象中的方法。例如:“”.toString()
等。
null 是空引用,表示一个对象的值,没有分配内存,调用 null 的字符串的方法会抛出空指针异常。例如如下代码:
String str = null;
System.out.println(str.length());
new String() 创建一个字符串对象的默认值为 “”,String 类型成员变量的初始值为 null。
空字符串 “” 是长度为 0 的字符串。可以调用以下代码检查一个字符串是否为空:
if (str.length() == 0)
或
if (str.equals(""))
空字符串是一个 Java 对象,有自己的串长度(0)和内容(空)。不过,String 变量还可以存放一个特殊的值,名为 null,这表示目前没有任何对象与该变量关联。要检查一个字符串是否为 null,要使用以下条件:
if (str == null)
有时要检查一个字符串既不是 null 也不为空串,这种情况下就需要使用以下条件:
if (str != null && str.length() != 0)
注意:首先要检查 str 不为 null。如果在一个 null 值上调用方法,会出现错误。
示例如下:
public static void main(String[] args) {
String str1 = new String();
String str2 = null;
String str3 = "";
System.out.println(str3.length()); // 空字符串""的长度为0
System.out.println(str2.length()); // 抛出空指针异常
System.out.println(str1); // 输出""
System.out.println(str1 == str2); // 内存地址的比较,返回false
System.out.println(str1.equals(str2)); // 值的比较,返回false
System.out.println(str2 == str3); // 内存地址的比较,返回false
System.out.println(str3.equals(str2)); // 值的比较,返回false
System.out.println(str1 == str3); // 内存地址的比较,返回false
System.out.println(str1.equals(str3)); // 值的比较,返回true
}
在给定的字符串中查找字符或字符串是比较常见的操作。字符串查找分为两种形式:一种是在字符串中获取匹配字符(串)的索引值,另一种是在字符串中获取指定索引位置的字符。
String 类的 indexOf() 方法和 lastlndexOf() 方法用于在字符串中获取匹配字符(串)的索引值。
indexOf() 方法用于返回字符(串)在指定字符串中首次出现的索引位置,如果能找到,则返回索引值,否则返回 -1。该方法主要有两种重载形式:
str.indexOf(value)
str.indexOf(value,int fromIndex)
其中,str 表示指定字符串;value 表示待查找的字符(串);fromIndex 表示查找时的起始索引,如果不指定 fromIndex,则默认从指定字符串中的开始位置(即 fromIndex 默认为 0)开始查找。
例如,下列代码在字符串“Hello Java”中查找字母 v 的索引位置。
String s = "Hello Java";
int size = s.indexOf('v'); // size的结果为8
上述代码执行后 size 的结果为 8,它的查找过程如图 1 所示。
编写一个简单的 Java 程序,演示 indexOf() 方法查找字符串的用法,并输出结果。代码如下:
public static void main(String[] args) {
String words = "today,monday,sunday";
System.out.println("原始字符串是'"+words+"'");
System.out.println("indexOf(\"day\")结果:"+words.indexOf("day"));
System.out.println("indexOf(\"day\",5)结果:"+words.indexOf("day",5));
System.out.println("indexOf(\"o\")结果:"+words.indexOf("o"));
System.out.println("indexOf(\"o\",6)结果:"+words.indexOf("o",6));
}
运行后的输出结果如下:
原始字符串是'today,monday,sunday'
indexOf("day")结果:2
indexOf("day",5)结果:9
indexOf("o")结果:1
indexOf("o",6)结果:7
lastIndexOf() 方法用于返回字符(串)在指定字符串中最后一次出现的索引位置,如果能找到则返回索引值,否则返回 -1。该方法也有两种重载形式:
str.lastIndexOf(value)
str.lastlndexOf(value, int fromIndex)
注意:lastIndexOf() 方法的查找策略是从右往左查找,如果不指定起始索引,则默认从字符串的末尾开始查找。
编写一个简单的 Java 程序,演示 lastIndexOf() 方法查找字符串的用法,并输出结果。代码如下:
public static void main(String[] args) {
String words="today,monday,Sunday";
System.out.println("原始字符串是'"+words+"'");
System.out.println("lastIndexOf(\"day\")结果:"+words.lastIndexOf("day"));
System.out.println("lastIndexOf(\"day\",5)结果:"+words.lastIndexOf("day",5));
System.out.println("lastIndexOf(\"o\")结果:"+words.lastIndexOf("o"));
System.out.println("lastlndexOf(\"o\",6)结果:"+words.lastIndexOf("o",6));
}
运行后的输出结果如下:
原始字符串是'today,monday,Sunday'
lastIndexOf("day")结果:16
lastIndexOf("day",5)结果:2
lastIndexOf("o")结果:7
lastlndexOf("o",6)结果:1
String 类的 charAt() 方法可以在字符串内根据指定的索引查找字符,该方法的语法形式如下:
字符串名.charAt(索引值)
提示:字符串本质上是字符数组,因此它也有索引,索引从零开始。
charAt() 方法的使用示例如下:
String words = "today,monday,sunday";
System.out.println(words.charAt(0)); // 结果:t
System.out.println(words.charAt(1)); // 结果:o
System.out.println(words.charAt(8)); // 结果:n
假设,在作业提交系统中学生需要录入提交的 Java 文件名称及要提交到的邮箱地址,那么就需要对学生输入的这些信息进行校验,判断输入是否有误。校验的规则为:录入的文件名称必须以“.java”结尾,录入的邮箱地址中必须包含有“@”符号和“.”符号,且“@”在“.”之前。
在这里使用 String 类中的 indexOf() 方法、charAt() 方法和 lastIndexOf() 方法来完成此程序。具体实现代码如下:
public static void main(String[] args) {
boolean filecon = false; // 判断文件名是否合法
boolean emailcon = false; // 判断邮箱地址是否合法
System.out.println("************ 欢迎进入作业提交系统 ************");
Scanner input = new Scanner(System.in);
System.out.println("请输入要提交的Java文件名称:");
String name = input.next(); // 获取输入的Java文件名
System.out.println("请输入要提交到的邮箱地址:");
String email = input.next(); // 获取输入的邮箱地址
// 检查输入的文件名是否合法
int index = name.lastIndexOf('.'); // 获取"n"所在的位置
// 判断合法
if (index != -1 && name.charAt(index + 1) == 'j' && name.charAt(index + 2) == 'a'
&& name.charAt(index + 3) == 'v' && name.charAt(index + 4) == 'a') {
filecon = true;
} else {
System.out.println("输入的文件名无效!");
}
// 检查邮箱地址是否合法
if (email.indexOf('@') != -1 && email.indexOf('.') > email.indexOf('@')) {
emailcon = true;
} else {
System.out.println("输入的邮箱地址无效!");
}
// 输出校验的结果
if (filecon && emailcon) {
System.out.println("作业提交成功!");
} else {
System.out.println("作业提交失败!");
}
}
运行该程序,当用户输入的文件名是以“.java”结尾,并且输入的邮箱地址中包含有“@”符号和“.”符号,“.”符号在“@”符号之后,才能检测通过,打印“作业提交成功!”, 如下所示:
************ 欢迎进入作业提交系统 ************
请输入要提交的Java文件名称:
answer.java
请输入要提交到的邮箱地址:
[email protected]
作业提交成功!
否则,打印“作业提交失败!”,如下所示:
************ 欢迎进入作业提交系统 ************
请输入要提交的Java文件名称:
abcjava
请输入要提交到的邮箱地址:
abcjava@qqcom
输入的文件名无效!
输入的邮箱地址无效!
作业提交失败!
在该程序中,首先使用 lastlndexOf() 方法获取用户输入 Java 文件中的所在的位置。因为 Java 文件是以“.java”结尾的,因此,可以使用 charAt() 方法来检测“.”之后的字符串是否是 java,即通过如下所示的条件判断表达式即可判断出用户输入的 Java 文件名是否以“.java”结尾。
index!=-1&&name.charAt(index+1)='j'
&&name.charAt(index+2)='a'
&&name.charAt(index+3)='v'
&&name.charAt(index+4)='a'
在检测邮箱地址是否合法时,首先使用了 indexOf() 方法判断用户输入的邮箱地址中是否含有符号,然后判断邮箱地址中的“.”符号是否在“@”符号之后,如果这两个条件都满足,则邮箱地址是合法的。
当文件名称和邮箱地址的检测都通过时,则打印“作业提交成功!”,否则打印“作业提交失败!”。
为了保证程序的安全,经常采用数据加密的方法。Java 中提供了专门用于加密运算的类和接口。
除了使用加密类和接口外,还可以通过多种方式实现字符串的加密。其中常用的就是获取字符串的字节数组,之后对字节数组中的每个字节都进行运算,得到新的内容,这时所获得的字符串与原字符串将不相同,以此达到加密的效果;解密时再将加密字符串进行相反的运算,这样即可得到原字符串。
本实例简单介绍如何通过数据运算实现字符串的加密和解密,实现步骤如下。
1)创建一个静态的 encryptAndDencrypt() 方法,在该方法中传入两个参数。代码如下:
public static String encryptAndDencrypt(String value, char secret) {
byte[] bt = value.getBytes(); // 将需要加密的内容转换为字节数组
for (int i = 0; i < bt.length; i++) {
bt[i] = (byte) (bt[i] ^ (int) secret); // 通过异或运算进行加密
}
String newresult = new String(bt, 0, bt.length); // 将加密后的字符串保存到 newresult 变量中
return newresult;
}
上述代码首先将需要加密的内容转换为字节数组,接着遍历字节数组中的内容,在 for 语句中通过异或运算进行加密,然后将加密后的字符串保存到 newresult 变量中。最后返回 newresult 变量的值。
2)在 main() 方法中添加代码,接收用户在控制台输入的内容并输出,然后调用 encryptAndUncrypt() 方法对字符串分别进行加密和解密,并将加密和解密后的内容输出。代码如下:
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
char secret = '8'; // 加密文字符
System.out.println("请输入您想加密的内容:");
String pass = scan.next();
System.out.println("原字符串内容:" + pass);
String encryptResult = encryptAndDencrypt(pass, secret);
System.out.println("加密后的内容:" + encryptResult);
String uncryptResult = encryptAndDencrypt(encryptResult, secret);
System.out.println("解密后的内容:" + uncryptResult);
}
3)执行上述代码进行测试,如下所示。
请输入您想加密的内容:
hello,java
原字符串内容:hello,java
加密后的内容:P]TTWRYNY
解密后的内容:hello,java
在 Java 中,除了通过 String 类创建和处理字符串之外,还可以使用 StringBuffer 类来处理字符串。StringBuffer 类可以比 String 类更高效地处理字符串。
因为 StringBuffer 类是可变字符串类,创建 StringBuffer 类的对象后可以随意修改字符串的内容。每个 StringBuffer 类的对象都能够存储指定容量的字符串,如果字符串的长度超过了 StringBuffer 类对象的容量,则该对象的容量会自动扩大。
StringBuffer 类提供了 3 个构造方法来创建一个字符串,如下所示:
使用 StringBuffer 类的构造函数的示例如下:
// 定义一个空的字符串缓冲区,含有16个字符的容量
StringBuffer str1 = new StringBuffer();
// 定义一个含有10个字符容量的字符串缓冲区
StringBuffer str2 = new StringBuffer(10);
// 定义一个含有(16+4)的字符串缓冲区,"青春无悔"为4个字符
StringBuffer str3 = new StringBuffer("青春无悔");
/*
*输出字符串的容量大小
*capacity()方法返回字符串的容量大小
*/
System.out.println(str1.capacity()); // 输出 16
System.out.println(str2.capacity()); // 输出 10
System.out.println(str3.capacity()); // 输出 20
上述代码声明了 3 个 StringBuffer 对象 str1、str2 和 str3,并分别对其进行初始化。str1.capacity() 用于查看 str1 的容量,接着以同样的方式对 str2 和 str3 进行容量查看的操作。
StringBuffer 类的 append() 方法用于向原有 StringBuffer 对象中追加字符串。该方法的语法格式如下:
StringBuffer 对象.append(String str)
该方法的作用是追加内容到当前 StringBuffer 对象的末尾,类似于字符串的连接。调用该方法以后,StringBuffer 对象的内容也发生了改变,例如:
StringBuffer buffer = new StringBuffer("hello,"); // 创建一个 StringBuffer 对象
String str = "World!";
buffer.append(str); // 向 StringBuffer 对象追加 str 字符串
System.out.println(buffer.substring(0)); // 输出:Hello,World!
每个新学期开始,学校都会针对本学期课程列出必修课程。编写一个 Java 程序,要求用户向控制台循环录入五门必修课程名称,并将这五个名称进行连接,最后输出连接后的字符串。代码如下:
import java.util.Scanner;
public class Testl9 {
public static void main(String[] args) {
StringBuffer sys = new StringBuffer("校内课程管理");
System.out.println("欢迎进入《"+sys+"》系统");
// 声明课程名称字符串
StringBuffer courseName = new StringBuffer();
System.out.println("请录入本期的五门必修课名称:");
Scanner input = new Scanner(System.in);
// 循环接收控制台输入的字符串
String name = "";
for (int i = 0;i < 5;i++) {
name = input.next();
courseName.append(name+"\t");
if(i == 4) {
System.out.println("录入完毕!");
}
}
System.out.println("本学期的必修课程有:\n"+courseName);
}
在该程序中,首先声明一个空的 StringBuffer 对象,然后声明并初始化 courseName 变量,该变量用于存储用户从控制台输入的课程名称,接着使用 for 循环语句来循环接收用户输入数据。在循环体中,调用 StringBuffer 对象的 append() 方法对用户输入的字符串进行追加,当用户录完五门课程的名称后,程序将输出“录入完毕!”的提示信息。最后输出 String-Buffer 对象字符串。
运行程序,执行结果如下所示:
欢迎进入《校内课程管理》系统
请录入本期的五门必修课名称:
Java语言基础
SQL查询数据库
模拟电路
Java面向对象编程
体育
录入完毕!
本学期的必修课程有:Java语言基础 SQL查询数据库 模拟电路 Java面向对象编程 体育
StringBuffer 类的 setCharAt() 方法用于在字符串的指定索引位置替换一个字符。该方法的语法格式如下:
StringBuffer 对象.setCharAt(int index, char ch);
该方法的作用是修改对象中索引值为 index 位置的字符为新的字符 ch,例如:
StringBuffer sb = new StringBuffer("hello");
sb.setCharAt(1,'E');
System.out.println(sb); // 输出:hEllo
sb.setCharAt(0,'H');
System.out.println(sb); // 输出:HEllo
sb.setCharAt(2,'p');
System.out.println(sb); // 输出:HEplo
StringBuffer 类中的 reverse() 方法用于将字符串序列用其反转的形式取代。该方法的语法格式如下:
StringBuffer 对象.reverse();
使用 StringBuffer 类中的 reverse() 方法对字符串进行反转的示例如下:
StringBuffer sb = new StringBuffer("java");
sb.reverse();
System.out.println(sb); // 输出:avaj
StringBuffer 类提供了 deleteCharAt() 和 delete() 两个删除字符串的方法,下面详细介绍。
deleteCharAt() 方法用于移除序列中指定位置的字符,该方法的语法格式如下:
StringBuffer 对象.deleteCharAt(int index);
deleteCharAt() 方法的作用是删除指定位置的字符,然后将剩余的内容形成一个新的字符串。例如:
StringBuffer sb = new StringBuffer("She");
sb.deleteCharAt(2);
System.out.println(sb); // 输出:Sh
执行该段代码,将字符串 sb 中索引值为 2 的字符删除,剩余的内容组成一个新的字符串,因此对象 sb 的值为 Sh。
delete() 方法用于移除序列中子字符串的字符,该方法的语法格式如下:
StringBuffer 对象.delete(int start,int end);
其中,start 表示要删除字符的起始索引值(包括索引值所对应的字符),end 表示要删除字符串的结束索引值(不包括索引值所对应的字符)。该方法的作用是删除指定区域以内的所有字符,例如:
StringBuffer sb = new StringBuffer("hello jack");
sb.delete(2,5);
System.out.println(sb); // 输出:he jack
sb.delete(2,5);
System.out.println(sb); // 输出:heck
执行该段代码,将字符串“hello jack”索引值为 2(包括)到索引值为 5(不包括)之间的所有字符删除,因此输出的新的字符串的值为“he jack”。
在本实例中为保证学生输入的 Java 文件名合格,将利用 StringBuffer 类实现对 Java 文件名中的特殊符号进行替换,包括将中文状态下的“。”和全角状态下的“.”替换为英文状态下的“.”。
在本例实现过程中主要使用了 StringBuffer 类的字符查找和替换方法,实现代码如下:
import java.util.Scanner;
public class test2 {
public static void main(String[] args) {
System.out.println("请输入你要提交的Java文件名称:");
Scanner input = new Scanner(System.in);
String fileName = input.next(); // 获取用户输入的 java 文件名称
// 定义StringBuffer对象,字符串内容为用户输入的java文件名称
StringBuffer file = new StringBuffer(fileName);
// 获取英文状态下的"."是否存在
int index = file.lastIndexOf(".");
// 判断中文状态下的"。"和"."是否存在
int errIndex1 = file.lastIndexOf("。");
int errIndex2 = file.lastIndexOf(".");
if (index != -1 && file.substring(index + 1, file.length()).equals("java")) {
System.out.println("作业提交成功!");
} else if (errIndex1 != -1 && file.substring(errIndex1 + 1, file.length()).equals("java")) {
// 将中文状态下的"。"改为英文状态下的"."
file.setCharAt(errIndex1, '.');
System.out.println("你的书写有误,已改正为:" + file + "\r\n提交成功!");
} else if (errIndex2 != -1 && file.substring(errIndex2 + 1, file.length()).equals("java")) {
// 将全角状态下的"."改为英文状态下的"."
file.setCharAt(errIndex2, '.');
System.out.println("你的书写有误,已改正为:" + file + "\r\n提交成功!");
} else {
System.out.println("你提供的java文件名称有误,请核实!");
}
}
}
运行该程序,当用户录入的 Java 文件名称中的为中文状态的“。”和“.”时,修改为英文状态下的“.”,然后再进行提交,如下所示:
请输入你要提交的Java文件名称:
myexapmle。java
你的书写有误,已改正为:myexample.java
在该程序中,实现替换特殊字符步骤如下所示:
在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。String 类是不可变类,即一旦一个 String 对象被创建以后,包含在这个对象中的字符序列是不可改变的,直至这个对象被销毁。
Java 提供了两个可变字符串类 StringBuffer 和 StringBuilder,中文翻译为“字符串缓冲区”。
StringBuilder 类是 JDK 1.5 新增的类,它也代表可变字符串对象。实际上,StringBuilder 和 StringBuffer 功能基本相似,方法也差不多。不同的是,StringBuffer 是线程安全的,而 StringBuilder 则没有实现线程安全功能,所以性能略高。因此在通常情况下,如果需要创建一个内容可变的字符串对象,则应该优先考虑使用 StringBuilder 类。
StringBuffer、StringBuilder、String 中都实现了 CharSequence 接口。CharSequence 是一个定义字符串操作的接口,它只包括 length()、charAt(int index)、subSequence(int start, int end) 这几个 API。
StringBuffer、StringBuilder、String 对 CharSequence 接口的实现过程不一样,如下图 1 所示:
可见,String 直接实现了 CharSequence 接口,StringBuilder 和 StringBuffer 都是可变的字符序列,它们都继承于 AbstractStringBuilder,实现了 CharSequence 接口。
String 是 Java 中基础且重要的类,被声明为 final class,是不可变字符串。因为它的不可变性,所以拼接字符串时候会产生很多无用的中间对象,如果频繁的进行这样的操作对性能有所影响。
StringBuffer 就是为了解决大量拼接字符串时产生很多中间对象问题而提供的一个类。它提供了 append 和 add 方法,可以将字符串添加到已有序列的末尾或指定位置,它的本质是一个线程安全的可修改的字符序列。
在很多情况下我们的字符串拼接操作不需要线程安全,所以 StringBuilder 登场了。StringBuilder 是 JDK1.5 发布的,它和 StringBuffer 本质上没什么区别,就是去掉了保证线程安全的那部分,减少了开销。
StringBuffer:线程安全
StringBuilder:线程不安全
一般情况下,速度从快到慢为 StringBuilder > StringBuffer > String,当然这是相对的,不是绝对的。
操作少量的数据使用 String。
单线程操作大量数据使用 StringBuilder。
多线程操作大量数据使用 StringBuffer。
正则表达式(Regular Expression)又称正规表示法、常规表示法,在代码中常简写为 regex、regexp 或 RE,它是计算机科学的一个概念。
正则表达式是一个强大的字符串处理工具,可以对字符串进行查找、提取、分割、替换等操作,是一种可以用于模式匹配和替换的规范。一个正则表达式就是由普通的字符(如字符 a~z)以及特殊字符(元字符)组成的文字模式,它用以描述在查找文字主体时待匹配的一个或多个字符串。
String 类里也提供了如下几个特殊的方法。
上面这些特殊的方法都依赖于 Java 提供的正则表达式支持,除此之外,Java 还提供了 Pattern 和 Matcher 两个类专门用于提供正则表达式支持。
很多读者都会觉得正则表达式是一个非常神奇、高级的知识,其实正则表达式是一种非常简单而且非常实用的工具。正则表达式是一个用于匹配字符串的模板。实际上,任意字符串都可以当成正则表达式使用。例如“abc”,它也是一个正则表达式,只是它只能匹配“abc”字符串。
如果正则表达式仅能匹配“abc”这样的字符串,那么正则表达式也就不值得学习了。正则表达式作为一个用于匹配字符串的模板,将某个字符模式与所搜索的字符串进行匹配。本文简单了解一下如何使用正则表达式来操作字符串。
创建正则表达式就是创建一个特殊的字符串。正则表达式所支持的合法字符如表 1 所示。
字符 | 解释 |
---|---|
X | 字符x(x 可代表任何合法的字符) |
\0mnn | 八进制数 0mnn 所表示的字符 |
\xhh | 十六进制值 0xhh 所表示的字符 |
\uhhhh | 十六进制值 0xhhhh 所表示的 Unicode 字符 |
\t | 制表符(“\u0009”) |
\n | 新行(换行)符(‘\u000A’) |
\r | 回车符(‘\u000D’) |
\f | 换页符(‘\u000C’) |
\a | 报警(bell)符(‘\u0007’) |
\e | Escape 符(‘\u001B’) |
\cx | x 对应的的控制符。例如,\cM 匹配 Ctrl-M。x 值必须为 A~Z 或 a~z 之一。 |
除此之外,正则表达式中有一些特殊字符,这些特殊字符在正则表达式中有其特殊的用途,比如前面介绍的反斜线\
。
如果需要匹配这些特殊字符,就必须首先将这些字符转义,也就是在前面添加一个反斜线\
。正则表达式中的特殊字符如表 2 所示。
特殊字符 | 说明 |
---|---|
$ | 匹配一行的结尾。要匹配 $ 字符本身,请使用\$ |
^ | 匹配一行的开头。要匹配 ^ 字符本身,请使用\^ |
() | 标记子表达式的开始和结束位置。要匹配这些字符,请使用\( 和\) |
[] | 用于确定中括号表达式的开始和结束位置。要匹配这些字符,请使用\[ 和\] |
{} | 用于标记前面子表达式的出现频度。要匹配这些字符,请使用\{ 和\} |
* | 指定前面子表达式可以出现零次或多次。要匹配 * 字符本身,请使用\* |
+ | 指定前面子表达式可以出现一次或多次。要匹配 + 字符本身,请使用\+ |
? | 指定前面子表达式可以出现零次或一次。要匹配 ?字符本身,请使用\? |
. | 匹配除换行符\n 之外的任何单字符。要匹配. 字符本身,请使用\. |
\ | 用于转义下一个字符,或指定八进制、十六进制字符。如果需匹配\ 字符,请用\\ |
| | 指定两项之间任选一项。如果要匹配丨 字符本身,请使用\| |
将上面多个字符拼起来,就可以创建一个正则表达式。例如:
“\u0041\\” // 匹配 A
“\u0061\t” // 匹配a<制表符>
“\?\[” // 匹配?[
注意:可能大家会觉得第一个正则表达式中怎么有那么多反斜杠?这是由于 Java 字符串中反斜杠本身需要转义,因此两个反斜杠(\)实际上相当于一个(前一个用于转义)。
上面的正则表达式依然只能匹配单个字符,这是因为还未在正则表达式中使用“通配符”,“通配符”是可以匹配多个字符的特殊字符。正则表达式中的“通配符”远远超出了普通通配符的功能,它被称为预定义字符,正则表达式支持如表 3 所示的预定义字符。
预定义字符 | 说明 |
---|---|
. | 可以匹配任何字符 |
\d | 匹配 0~9 的所有数字 |
\D | 匹配非数字 |
\s | 匹配所有的空白字符,包括空格、制表符、回车符、换页符、换行符等 |
\S | 匹配所有的非空白字符 |
\w | 匹配所有的单词字符,包括 0~9 所有数字、26 个英文字母和下画线_ |
\W | 匹配所有的非单词字符 |
上面的 7 个预定义字符其实很容易记忆,其中:
有了上面的预定义字符后,接下来就可以创建更强大的正则表达式了。例如:
c\wt // 可以匹配cat、cbt、cct、cOt、c9t等一批字符串
\d\d\d-\d\d\d-\d\d\d\d // 匹配如 000-000-0000 形式的电话号码
在一些特殊情况下,例如,若只想匹配 a~f 的字母,或者匹配除 ab 之外的所有小写字母,或者匹配中文字符,上面这些预定义字符就无能为力了,此时就需要使用方括号表达式,方括号表达式有如表 4 所示的几种形式。
方括号表达式 | 说明 |
---|---|
表示枚举 | 例如[abc] 表示 a、b、c 其中任意一个字符;[gz] 表示 g、z 其中任意一个字符 |
表示范围:- | 例如[a-f] 表示 a~f 范围内的任意字符;[\\u0041-\\u0056] 表示十六进制字符 \u0041 到 \u0056 范围的字符。范围可以和枚举结合使用,如[a-cx-z] ,表示 ac、xz 范围内的任意字符 |
表示求否:^ | 例如[^abc] 表示非 a、b、c 的任意字符;[^a-f] 表示不是 a~f 范围内的任意字符 |
表示“与”运算:&& | 例如 [a-z&&[def]] 是 a~z 和 [def] 的交集,表示 d、e f[a-z&&^bc]] 是 a~z 范围内的所有字符,除 b 和 c 之外 [ad-z] [a-z&&[m-p]] 是 a~z 范围内的所有字符,除 m~p 范围之外的字符 |
表示“并”运算 | 并运算与前面的枚举类似。例如[a-d[m-p]] 表示 [a-dm-p] |
方括号表达式比前面的预定义字符灵活多了,几乎可以匹配任何字符。例如,若需要匹配所有的中文字符,就可以利用 [\u0041-\u0056] 形式——因为所有中文字符的 Unicode 值是连续的,只要找出所有中文字符中最小、最大的 Unicode 值,就可以利用上面形式来匹配所有的中文字符。
正则表达式还支持圆括号,用于将多个表达式组成一个子表达式,圆括号中可以使用或运算符|
。例如,正则表达式“((public)|(protected)|(private))”用于匹配 Java 的三个访问控制符其中之一。
除此之外,Java 正则表达式还支持如表 5 所示的几个边界匹配符。
边界匹配符 | 说明 |
---|---|
^ | 行的开头 |
$ | 行的结尾 |
\b | 单词的边界 |
\B | 非单词的边界 |
\A | 输入的开头 |
\G | 前一个匹配的结尾 |
\Z | 输入的结尾,仅用于最后的结束符 |
\z | 输入的结尾 |
前面例子中需要建立一个匹配 000-000-0000 形式的电话号码时,使用了 \d\d\d-\d\d\d-\d\d\d\d 正则表达式,这看起来比较烦琐。实际上,正则表达式还提供了数量标识符,正则表达式支持的数量标识符有如下几种模式。
三种模式的数量表示符如表 6 所示。
贪婪模式 | 勉强模式 | 占用模式 | 说明 |
---|---|---|---|
X? | X?? | X?+ | X表达式出现零次或一次 |
X* | X*? | X*+ | X表达式出现零次或多次 |
X+ | X+? | X++ | X表达式出现一次或多次 |
X{n} | X{n}? | X{n}+ | X表达式出现 n 次 |
X{n,} | X{n,}? | X{n,}+ | X表达式最少出现 n 次 |
X{n,m} | X{n,m}? | X{n,m}+ | X表达式最少出现 n 次,最多出现 m 次 |
关于贪婪模式和勉强模式的对比,看如下代码:
String str = “hello,java!”;
// 贪婪模式的正则表达式
System.out.println(str.replaceFirst("\w*" , “■”)); //输出■,java!
// 勉强模式的正则表达式
System.out.println(str.replaceFirst("\w*?" , “■”")); //输出■hello, java!
当从“hello java!”字符串中查找匹配\\w*
子串时,因为\w*
使用了贪婪模式,数量表示符*
会一直匹配下去,所以该字符串前面的所有单词字符都被它匹配到,直到遇到空格,所以替换后的效果是“■,Java!”;如果使用勉强模式,数量表示符*
会尽量匹配最少字符,即匹配 0 个字符,所以替换后的结果是“■hello,java!”。
java.util.regex 是一个用正则表达式所订制的模式来对字符串进行匹配工作的类库包。它包括两个类:Pattern 和 Matcher。
Pattern 对象是正则表达式编译后在内存中的表示形式,因此,正则表达式字符串必须先被编译为 Pattern 对象,然后再利用该 Pattern 对象创建对应的 Matcher 对象。执行匹配所涉及的状态保留在 Matcher 对象中,多个 Matcher 对象可共享同一个 Pattern 对象。
因此,典型的调用顺序如下:
// 将一个字符串编译成 Pattern 对象
Pattern p = Pattern.compile(“a*b”);
// 使用 Pattern 对象创建 Matcher 对象
Matcher m = p.matcher(“aaaaab”);
boolean b = m.matches(); // 返回 true
上面定义的 Pattern 对象可以多次重复使用。如果某个正则表达式仅需一次使用,则可直接使用 Pattern 类的静态 matches() 方法,此方法自动把指定字符串编译成匿名的 Pattern 对象,并执行匹配,如下所示。
boolean b = Pattern.matches (“a*b”,“aaaaab”); // 返回 true
上面语句等效于前面的三条语句。但采用这种语句每次都需要重新编译新的 Pattern 对象,不能重复利用已编译的 Pattern 对象,所以效率不高。Pattern 是不可变类,可供多个并发线程安全使用。
Matcher 类提供了几个常用方法,如表 1 所示。
名称 | 说明 |
---|---|
find() | 返回目标字符串中是否包含与 Pattern 匹配的子串 |
group() | 返回上一次与 Pattern 匹配的子串 |
start() | 返回上一次与 Pattern 匹配的子串在目标字符串中的开始位置 |
end() | 返回上一次与 Pattern 匹配的子串在目标字符串中的结束位置加 1 |
lookingAt() | 返回目标字符串前面部分与 Pattern 是否匹配 |
matches() | 返回整个目标字符串与 Pattern 是否匹配 |
reset() | 将现有的 Matcher 对象应用于一个新的字符序列。 |
在 Pattern、Matcher 类的介绍中经常会看到一个 CharSequence 接口,该接口代表一个字符序列,其中 CharBuffer、String、StringBuffer、StringBuilder 都是它的实现类。简单地说,CharSequence 代表一个各种表示形式的字符串。
通过 Matcher 类的 find() 和 group() 方法可以从目标字符串中依次取出特定子串(匹配正则表达式的子串),例如互联网的网络爬虫,它们可以自动从网页中识别出所有的电话号码。下面程序示范了如何从大段的字符串中找出电话号码。
public class FindGroup {
public static void main(String[] args) {
// 使用字符串模拟从网络上得到的网页源码
String str = "我想找一套适合自己的JAVA教程,尽快联系我13500006666" + "交朋友,电话号码是13611125565" + "出售二手电脑,联系方式15899903312";
// 创建一个Pattern对象,并用它建立一个Matcher对象
// 该正则表达式只抓取13X和15X段的手机号
// 实际要抓取哪些电话号码,只要修改正则表达式即可
Matcher m = Pattern.compile("((13\\d)|(15\\d))\\d{8}").matcher(str);
// 将所有符合正则表达式的子串(电话号码)全部输出
while (m.find()) {
System.out.println(m.group());
}
}
}
运行上面程序,看到如下运行结果:
13500006666
13611125565
15899903312
从上面运行结果可以看出,find() 方法依次查找字符串中与 Pattern 匹配的子串,一旦找到对应的子串,下次调用 find() 方法时将接着向下查找。
提示:通过程序运行结果可以看出,使用正则表达式可以提取网页上的电话号码,也可以提取邮件地址等信息。如果程序再进一步,可以从网页上提取超链接信息,再根据超链接打开其他网页,然后在其他网页上重复这个过程就可以实现简单的网络爬虫了。
find() 方法还可以传入一个 int 类型的参数,带 int 参数的 find() 方法将从该 int 索引处向下搜索。start() 和 end() 方法主要用于确定子串在目标字符串中的位置,如下程序所示。
public class StartEnd {
public static void main(String[] args) {
// 创建一个Pattern对象,并用它建立一个Matcher对象
String regStr = "Java is very easy!";
System.out.println("目标字符串是:" + regStr);
Matcher m = Pattern.compile("\\w+").matcher(regStr);
while (m.find()) {
System.out.println(m.group() + "子串的起始位置:" + m.start() + ",其结束位置:" + m.end());
}
}
}
上面程序使用 find()、group() 方法逐项取出目标字符串中与指定正则表达式匹配的子串,并使用 start()、end() 方法返回子串在目标字符串中的位置。运行上面程序,看到如下运行结果:
目标字符串是:Java is very easy!
Java子串的起始位置:0,其结束位置:4
is子串的起始位置:5,其结束位置:7
very子串的起始位置:8,其结束位置:12
easy子串的起始位置:13,其结束位置:17
matches() 和 lookingAt() 方法有点相似,只是 matches() 方法要求整个字符串和 Pattern 完全匹配时才返回 true,而 lookingAt() 只要字符串以 Pattern 开头就会返回 true。reset() 方法可将现有的 Matcher 对象应用于新的字符序列。看如下例子程序。
public class MatchesTest {
public static void main(String[] args) {
String[] mails = { "[email protected]", "[email protected]", "[email protected]", "[email protected]" };
String mailRegEx = "\\w{3,20}@\\w+\\.(com|org|cn|net|gov)";
Pattern mailPattern = Pattern.compile(mailRegEx);
Matcher matcher = null;
for (String mail : mails) {
if (matcher == null) {
matcher = mailPattern.matcher(mail);
} else {
matcher.reset(mail);
}
String result = mail + (matcher.matches() ? "是" : "不是") + "一个有效的邮件地址!";
System.out.println(result);
}
}
}
上面程序创建了一个邮件地址的 Pattern,接着用这个 Pattern 与多个邮件地址进行匹配。当程序中的 Matcher 为 null 时,程序调用 matcher() 方法来创建一个 Matcher 对象,一旦 Matcher 对象被创建,程序就调用 Matcher 的 reset() 方法将该 Matcher 应用于新的字符序列。
从某个角度来看,Matcher 的 matches()、lookingAt() 和 String 类的 equals() 有点相似。区别是 String 类的 equals() 都是与字符串进行比较,而 Matcher 的 matches() 和 lookingAt() 则是与正则表达式进行匹配。
事实上,String 类里也提供了 matches() 方法,该方法返回该字符串是否匹配指定的正则表达式。例如:
“[email protected]”.matches("\w{3,20}@\w+\.(com|org|cn|net|gov)"); // 返回 true
除此之外,还可以利用正则表达式对目标字符串进行分割、查找、替换等操作,看如下例子程序。
public class ReplaceTest {
public static void main(String[] args) {
String[] msgs = { "Java has regular expressions in 1.4", "regular expressions now expressing in Java",
"Java represses oracular expressions" };
Pattern p = Pattern.compile("re\\w*");
Matcher matcher = null;
for (int i = 0; i < msgs.length; i++) {
if (matcher == null) {
matcher = p.matcher(msgs[i]);
} else {
matcher.reset(msgs[i]);
}
System.out.println(matcher.replaceAll("哈哈:)"));
}
}
}
上面程序使用了 Matcher 类提供的 replaceAll() 把字符串中所有与正则表达式匹配的子串替换成“哈哈:)”,实际上,Matcher 类还提供了一个 replaceFirst(),该方法只替换第一个匹配的子串。运行上面程序,会看到字符串中所有以“re”开头的单词都会被替换成“哈哈:)”。
实际上,String 类中也提供了 replaceAll()、replaceFirst()、split() 等方法。下面的例子程序直接使用 String 类提供的正则表达式功能来进行替换和分割。
public class StringReg {
public static void main(String[] args) {
String[] msgs = { "Java has regular expressions in 1.4", "regular expressions now expressing in Java",
"Java represses oracular expressions" };
for (String msg : msgs) {
System.out.println(msg.replaceFirst("re\\w*", "哈哈:)"));
System.out.println(Arrays.toString(msg.split(" ")));
}
}
}
上面程序只使用 String 类的 replaceFirst() 和 split() 方法对目标字符串进行了一次替换和分割。运行上面程序,会看到如下所示的输出结果。
Java has 哈哈:) expressions in 1.4
[Java, has, regular, expressions, in, 1.4]
哈哈:) expressions now expressing in Java
[regular, expressions, now, expressing, in, Java]
Java 哈哈:) oracular expressions
[Java, represses, oracular, expressions]
正则表达式是一个功能非常灵活的文本处理工具,增加了正则表达式支持后的 Java,可以不再使用 StringTokenizer 类(也是一个处理字符串的工具,但功能远不如正则表达式强大)即可进行复杂的字符串处理。
在注册会员时,经常需要输入电话号码,电话号码是指手机号码或者固定电话。如果输入的内容不合法,则会向用户输出提示。本实例模拟实现电话号码的验证功能,接收用户在控制台输入的电话号码,然后进行判断,并将结果输出。
在这里使用《Java正则表达式》一节中讲到的正则表达式支持的字符来实现,步骤如下。
(1) 创建名为 Test21.java 的 Java 文件,在 main() 方法中开始编写代码。
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Text21 {
public static void main(String[] args) {
//编写代码
}
}
(2) 声明 String 类型的 regex 变量,它是用于验证电话号码的表达式。代码如下:
String regex = "0\\d{2,3}[-]?\\d{7,8}|0\\d{2,3}\\s?\\d{7,8}|13[0-9]\\d{8}|15[1089]\\d{8}";
电话号码包括固定电话和手机号码。其中固定电话是由区号和号码组成,区号是以 0 开头的,后面是 2~3 位数,因此在匹配区号的时候可以使用正则表达式0\d{2,3}
。固定电话号码由 7~8 位数字组成,因此可以使用表达式\d{7,8}
来进行匹配。固定电话的组合方式可能是“区号-号码”或者是“区号号码”,因此匹配固定电话号码时,可以使用“0\d{2,3}[-]?\d{7,8}|0\d{2,3}\s?\d{7,8}”表达式。
手机号码是 11 位数,并且以数字 1 开头。考虑到手机号码的特殊性,这里使用“13[0-9]\d{8}|15[1089]\d{8}”表达式进行匹配。该正则表达式验证以 13 或 15 开头的手机号码; 以 15 开头的电话号码,第 3 位数字只能是 1、0、8、9 中的一个。
(3) 声明 String 类型的 answer 变量,它表示是否继续验证电话号码。代码如下:
String answer = "Y";
(4) 使用 do…while 语句进行操作,首先接收用户在控制台输入的电话号码,然后利用 Pattern 类进行编译,接着创建给定输入模式的匹配器,调用 matches() 方法返回匹配的结果。如果结果为 true 表示验证通过,如果为 false 表示验证失败。代码如下:
do {
System.out.print("请留下您的电话号码:");
Scanner scan = new Scanner(System.in);
String phone = scan.next(); // 接收用户在控制台输入的电话号码
Pattern pattern = Pattern.compile(regex); // 编译正则表达式
Matcher matcher = pattern.matcher(phone); // 创建给定输入模式的匹配器
boolean bool = matcher.matches();
if(bool) { // 如果验证通过
System.out.println("输入的电话号码格式正确。");
} else {
System.out.println("输入的电话号码无效,格式不正确。");
}
System.out.print("是否继续输入?(Y/N 或者 y/n)");
answer=scan.next();
}while(answer.equalsIgnoreCase("Y"));
System.out.println("注册结束。");
(5) 运行代码进行测试,如下所示:
请留下您的电话号码:18812345678
输入的电话号码无效,格式不正确。
是否继续输入?(Y/N 或者 y/n)y
请留下您的电话号码:180112345678
输入的电话号码无效,格式不正确。
是否继续输入?(Y/N 或者 y/n)n
注册结束。
请留下您的电话号码:010-12345678
输入的电话号码格式正确。
是否继续输入?(Y/N 或者 y/n)y
请留下您的电话号码:010-123456789
输入的电话号码无效,格式不正确。
是否继续输入?(Y/N 或者 y/n)y
请留下您的电话号码:0388-12345678
输入的电话号码格式正确。
是否继续输入?(Y/N 或者 y/n)n
注册结束。
IP 地址是网络上每台计算机的唯一标识,因此 IP 地址的错误输入将使程序无法运行。下面使用前面学习的正则表达式知识,编写一个 Java 程序来验证 IP 地址是否合法。
在定义正则表达式之前,首先要知道一个正确 IP 地址的格式及组成部分。IP 地址由 4 字节构成,每字节的值为 0~255,各字节通过一个句点分隔。因此,IP 地址中的每字节有至少一个,至多三个数字。
下面是为 IP 地址编写的正则表达式:
\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}
以上正则表达式对 IP 做简单的匹配,不完全和 IP 的规则一致。如果想完全匹配,读者可以重新修改匹配的正则表达式。
创建 Test22 类,在该类的 main() 方法中编写验证 IP 地址的代码。代码如下:
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Test22 {
public static void main(String[] args) {
String regex = "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}";
String answer = "Y";
do {
System.out.print("请输入 IP 地址:");
Scanner scan = new Scanner(System.in);
String phone = scan.next(); // 接收用户在控制台输入的电话号码
Pattern pattern = Pattern.compile(regex); // 编译正则表达式
Matcher matcher = pattern.matcher(phone); // 创建给定输入模式的匹配器
boolean bool = matcher.matches();
if(bool) { // 如果验证通过
System.out.println("输入的 IP 地址正确。");
} else {
System.out.println("输入的IP地址格式错误。");
}
System.out.print("是否继续输入?(Y/N 或者 y/n)");
answer = scan.next();
}while(answer.equalsIgnoreCase("Y"));
System.out.println("程序结束。");
}
}
运行程序,然后输入不同格式的 IP 地址,输出结果如下所示:
请输入 IP 地址:11.154.15.1
输入的 IP 地址正确。
是否继续输入?(Y/N 或者 y/n)y
请输入 IP 地址:22a.7.68.9
输入的IP地址格式错误。
是否继续输入?(Y/N 或者 y/n)n
程序结束。