JAVA字符串详解

10. 字符串

10.1 字符串类 String

字符串其实就是若干字符组成的有序序列。

在String类中,维护了一个字符数组,字符串数组的存储其本质是实现一个字符数组。

10.1.1 字符串类型的内存分析

字符串是一个类,同时也是一个引用数据类型,但区别于其他类或者接口(表现之一:直接给字符串赋值时,其空间开辟不在堆上而在常量池上开辟,而常量池隶属于方法区;而通过构造方法实例化的字符串则是在堆上开辟空间并指向方法池)。

双引号就代表在常量池上指引内容。

字符串中遵循享元原则:第一次使用到某字符串时,在常量池中会将字母排列组合,将地址引用赋值,自此以后每当再使用该字符串时,将原地址给调用方赋值。

例:

String string = "hello";
String string2 = "hello";
String string3 = new String("hello");
//true,理由是存储在方法池上的字母已经有hello排序,再次赋值直接赋地址,故地址相同
System.out.println(string ==string2); 	
//false,理由是构造方法实例化的字符串地址在堆上而非方法池中
System.out.println(string ==string3);
//true,理由是equals方法比较的是数组而非地址
System.out.println(string.equals(string3));
10.1.2 字符串常用的方法

构造方法

String str1 = new String();		//实例化一个空字符串
String str2 = new String("123");//通过一个字符串实例化一个字符串对象
String str3 = new String(new char[] {'a','b','c'});//通过一个字符数组实例化一个字符串对象
int offset = 0,count = 3;
String str4 = new String(new char[] {'a','b','c','d','e'},offset,count);//从第offset第索引/*
* 通过⼀个字节数组,实例化⼀个字符串
* new String(byte[] array)
* 通过⼀个字节数组的指定部分,实例化⼀个字符串
* new String(byte[] array, int offset, int length);
* 通过⼀个字节数组,使⽤指定的字符集实例化⼀个字符串
* new String(byte[] array, String charsetName)
* 通过⼀个字节数组的指定部分,使⽤指定的字符集实例化⼀个字符串
* new String(byte[] array, int offset, int length, String charsetName);
*
* 通过⼀个StringBuffer实例化⼀个字符串
* new String(StringBuffer sb);
* 通过⼀个StringBuilder实例化⼀个字符串
* new String(StringBuilder sb);
*/

非静态方法

这些⽅法,基本都是对⼀个字符串进⾏操作的⽅法。但是,由于字符串是⼀个常量,内容是不能改变

的,因此每⼀个修改字符串的⽅法,都是需要接收返回值来得到新的结果的。

//1.将两个字符串拼接到⼀起,这个过程中,会new⼀个新的字符串对象,并返回结果
String ret1 = str1 + str2;
//2.将两个字符串拼接到⼀起,这个过程中,会new⼀个新的字符串对象,并返回结果
String ret2 = str1.concat(str2);
//3.从指定的下标位开始截取字符串,⼀直到最后⼀位,此时,结果为 "llo"
String ret3 = str1.substring(2);
//4.截取⼀个字符串的指定范围 [fromIndex, endIndex),此时,结果为 "ll"
String ret4 = str1.substring(2, 4);
//5.截取⼀个字符序列的指定范围 [fromIndex, endIndex),返回值CharSequence是⼀个接⼝
CharSequence ret5 = str1.subSequence(2, 4);
//6.将一个字符串中固定的字符序列替换成新的字符序列
	String string6 = "hello world".replace('l', 'L');
	String string6_1 = "hello world".replace("el", "ELLLL");
	//除去字符串中所有空格
	String string6_2 = "       hello world    ".replace(" ", "");
//7.将一个字符串转成一个字符数组
char[]array7 = "hello world".toCharArray();
String string7= Arrays.toString(array7);
//8.1将⼀个字符串转成⼀个字节数组,以项⽬默认的字符集进⾏转换
byte[] array8_1 = str1.getBytes();
//8.2将一个字符串转成指定的字节数组
try {
     byte[] array8_2 = str1.getBytes("utf8");
    } catch (UnsupportedEncodingException e) {
     e.printStackTrace();
}
//9.下标查询(若查询失败则返回-1)
	//9.1查询目标字符/字符串在字符串中第一次出现的下标
	int index9_1 = "hello world".indexOf("ll");
	//9.2查询目标字符/字符串在字符串中最后一次出现的下标
	int index9_2 = "hello world".lastIndexOf("ll");
	//9.3查询目标字符/字符串自第count位起第一次出现的下标
	int index9_3 = "hello world".indexOf("ll",count);
	//9.4查询目标字符/字符串自第count位起最后一次出现的下标
	int index9_4 = "hello world".lastIndexOf("ll",count);
/*
* 以下四个查询下标的⽅法,和上⽅查询字符下标的逻辑是⼀模⼀样的
* 查询到的下标是字符串中的第0个字符的下标
*
* indexOf(String str)
* indexOf(String str, int fromIndex)
* lastIndexOf(String str)
* lastIndexOf(String str, int fromIndex)
*/
//10.大小写转换
	//10.1小写转大写
	String string10_1 = "hello world".toUpperCase();	
	//10.2大写转小写
	String string10_2 = "HELLO WORLD".toLowerCase();	
//11.获取字符串的长度
int length11 = "hello world".length();
//12.判断字符串是否为空
boolean boolean12 = "".isEmpty();
//13.判断⼀个字符串中是否包含指定的⼦字符串
boolean ret13 = str1.contains("ll");
//14.判断一个字符串的前后缀
	//14.1判断一个字符串是否以目标字符串开头
	boolean boolean14_1 = "hello world".startsWith("he");
	//14.2判断一个字符串是否以目标字符串结尾
	boolean boolean14_2 = "hello world".endsWith("ld");
//15.判断一个字符串是否包含目标字符串
boolean boolean15 = "hello world".contains("lo");
//16.判断两个字符串的内容是否相同
	boolean boolean16_1 = "hello world".equals("hello world");
	//忽略大小写做判断
	boolean boolean16_2 = "hello world".equalsIgnoreCase("HELLO WORLD");
//17.除去字符串前后两端的空格
String string17 = "      hello world      ".trim();
//18.字符串的比较:
//依次从前往后比较相同索引字符的ASCII码值,直至某索引的字符可以比较出大小或字符串结束。
	int int18_1 = "hello".compareTo("HELLO");			//返回首次出现的非零ASCII差值或者返回0
	int int18_2 = "hello".compareToIgnoreCase("HELLO");	//忽略大小写进行比较(所有大写均视为小写)
//19.字符串格式化:将若干变量的内容按照一定的格式拼接到一个字符串中,例:
String name19 = "xiaoming";int age15 = 10;char gender15 = '男';
// 拼成:姓名:xiaoming ,性别:男,年龄:10岁
//在format方法中可以定制一个字符串的格式,在格式字符串中,可以使用指定符号进行占位。
String string19_1 = String.format("姓名:%s ,性别:%c,年龄:%d岁", name19_1,gender19_1,age19_1);
//20.字符串切割:按照指定字符切割字符串,例:下列字符串按逗号切割成字符串数组
String[] strings20 = "xiaoming,xiaohong,xiaoli,xiaolan,xiaohei,xiaobai".split(",");

静态方法

String ret = String.join(", ", "xiaoming", "xiaobai", "xiaohei", "xiaolv");
System.out.println(ret);
10.2 StringBuffer、StringBuilder

StringBuffer:字符串缓冲池,线程安全的可变序列。

int index = 5,start = 5,end= 11;char ch = ' ';String str = "@";
//实例化一个StringBuffer类的空字符串对象
StringBuffer sb = new StringBuffer();
//通过一个字符串字面量来实例化一个StringBuffer类的字符串对象
StringBuffer stringBuffer = new StringBuffer("hello world");
//常规操作
//1.增:在对象自身的尾部拼接一个新的字符串
stringBuffer.append("!");
//2.增:在索引位插入一个新的字符串str
stringBuffer.insert(index, str);
//3.删:删除[start,end)索引范围的元素
stringBuffer.delete(start, end);
//4.删:删除索引位上的元素
stringBuffer.deleteCharAt(5);
//5.改:将[start,end)索引范围的元素改成字符串str
stringBuffer.replace(start, end, str);
//6.改:将索引位的元素修改为字符ch
stringBuffer.setCharAt(index, ch);
//7.字符串倒置:将字符串中所有字符逆序组合排列
stringBuffer.reverse();
//8.StringBuffer类型->String类型:
String string = stringBuffer.toString();

StringBuilder:字符串构建器,线程不安全的可变序列,是使用工厂模式实现的字符串的常见操作。

StringBuilder常见方法的使用与StringBuffer完全相同

两者区别:StringBuffer线程安全,代码同步,而StringBuilder线程不安全,因为没有做代码同步,但比StringBuffer高效,因此在不考虑线程安全的情况(例:单线程中),推荐使用StringBuilder。

补充:在字符串的操作中三者效率:StringBuilder > StringBuffer >>> String。

10.3 正则表达式

正则表达式不是Java特有的内容,是一种独立的表达式,其主要作用是:做字符串的校验,具体做法是:指定一些字符串应遵循的规则并判断是否满足这些规则,在校验的基础上,⼜添加了若⼲个其他的引⽤场景,例如: 批量的查找、替换、切割…。

使用关键字:matches 用于判断指定字符串是否满足正则表达式的规则,语法

字符串对象.matches(正则表达式);
10.3.1 正则表达式中的基本元字符

Java中的正则表达式支持的元字符如下:

(用于分组) [用于限定单个元素的校验] {用于限定次数} \用于转义 ^行首或非 $行尾 |或 ?出现0次或1次 *出现0次或多次 +出现1次或多次 .通配 < > - = !
[]字符类的使用示例含义
[abc]字符a,b或c
[^xyz]除x,y和z以外的字符
[a-z]字符a到z
[a-cx-z]字符a到c或x到z,其将包括a,b,c,x,y或z。
[0-9&&[4-8]]两个范围(4,5,6,7或8)的交叉,
[a-z&&[^aeiou]]所有小写字母减元音

分组相关字符

元字符用处
()分组符号
$n第n组

下表列出了一些常用的预定义字符类

含义
.任何字符
\d数字。 与[0-9]相同
\D非数字。 与[^ 0-9]相同
\s空格字符。 包括与[\ t \ n \ x0B \ f \ r]相同。空格标签换行符垂直标签表单Feed回车字符
\S非空白字符。 与[^ \ s]相同
\w一个字符。 与[a-zA-Z_0-9]相同。
\W非字字符。 与[^ \ w]相同。

我们可以使用量词判断该量词前一个或一串字符是否满足规则,下面列出了量词及其含义。

量词意味该量词前一位或一串字符连续出现
*零次一次或多次(全情况均true)
+一次或多次
一次或根本不
{m}正好m次
{m,}至少m次
{m,n}至少m,但不超过n次

要匹配一行的开头,或匹配整个单词,不是任何单词的一部分,我们必须为匹配器设置边界。

下表列出了正则表达式中的边界匹配器

边界匹配含义
^一行的开始
$一行的结束
\b字边界
\B非字边界
\A输入的开始
\G上一次匹配的结束
\Z输入的结束,但是对于最终终止符,如果有的话
\z输入的结束
10.3.2 元字符的实际使用案例

万事不会问度娘

// []
// 验证⼀个字符串是否以⼩写字⺟开头
System.out.println("Hello world".matches("[a-z]ello world"));
// 验证⼀个字符串是否以字⺟开头(包括⼤写字⺟和⼩写字⺟)
System.out.println("Hello world".matches("[a-zA-Z]ello world"));
// 验证⼀个字符串是否是以⾮⼤写字⺟开头的
System.out.println("hello world".matches("[^A-Z]ello world"));
// 验证⼀个字符串是否是以(任意的⾮⼩写字⺟,但是 h 除外)开头的
System.out.println("hello world".matches("[^a-z[h]]ello world"));
// 验证⼀个字符串是否以字符 . 作为开头的
System.out.println(".ello world".matches("\\.ello world"));
// 验证⼀个字符串是否以数字开头
System.out.println("9e".matches("\\de"));
// 验证l出现了1次或多次
System.out.println("hellllllllllo".matches("hel+o"));
// 验证l出现了1次或0次
System.out.println("heo".matches("hel?o"));
// 验证l出现了0次或多次
System.out.println("helo".matches("hel*o"));
// 验证l出现了3次
System.out.println("helllo".matches("hel{3}o"));
// 验证l出现了⾄少3次
System.out.println("helllllllllo".matches("hel{3,}o"));
// 验证l出现了3次到5次 [3,5]
System.out.println("helllllo".matches("hel{3,5}o"));
10.3.3 正则表达式的实际案例
//常见方法
//1.利用正则表达式指定切割规则
String names = "Lily      ,    Lucy  ,Polly    ,Jim  Green, uncle wang    ,Hanmeimei    ";
String[] namesArray = names.split(", *");
for(String n :namesArray) {
    System.out.println(n);
}
//2.利用正则表达式指定替换规则
String result2 = names.replaceAll(" *, *", ", ");
System.out.println(result2);
//3.利用正则表达式分组并替换,例:18720867688 ->187****7688
String phone3 = "18720867688";
String regex = "^(1[4678]\\d)(\\d{4})(\\d{4})$";
String result3 = phone3.replaceAll(regex, "$1****$3");
System.out.println(result3);
//4.|:或 
//例:根据拓展名判断一个文件是否是视频文件:.mp4,.rmb,.avi,.mkv,.rm
String vedioname4 = "Harry Potter.avi";
String regex4 = "^(.+)\\.(mp4|rmb|mkv|rm|avi)$";
boolean result4 = vedioname4.matches(regex4);
System.out.println(result4);

案例1:字符串校验

// 1、QQ号的校验
// "[0-9]\\d{4,10}"
// 2、⼿机号
// 1[35678]\\d{9}

案例2:字符串切割

// 字符串的切割
String str = "xiaoming xiaoli xiaohong xiaobai";
String[] names = str.split(" +");
System.out.println(names.length);
for (String name : names) {
 	System.out.println(name);
}

案例3:字符串替换

// 字符串的替换
// replaceAll(String regex, String replacement)
// 将⼀个字符串中的所有的满⾜正则规则部分的字符串,替换成指定的字符串
// replaceFirst(String regex, String replacement)
// 将⼀个字符串中的第⼀个满⾜正则规则部分的字符串,替换成指定的字符串
String ret = str.replaceAll("[#*$]+", ", ");
System.out.println(ret);

注意:

1.编译全程无提示,书写需小心,千万不能加空格。

2.凡是字符串对象中出现元字符而产生歧义时,需要在改元字符前加双斜杠进行双转义,例:

"hello[world]".matches("^hello\\[world]$");
10.4 Pattern类和Matcher

Pattern类用来制定正则表达式的规则,Matcher类用来承接结果,二者往往一起使用。

10.4.1 Pattern类

其实,这个类,才是真正来操作正则表达式的类。在String类中的提供的 matches、split、replace等⽅法,其实都是对这个类中的某些⽅法的封装。

10.4.2 Matcher类

Pattern类⽤来做校验、匹配的⼀个结果。

// Pattern 类的使用
        // boolean ret = Pattern.matches("\\d+", "123456");
        // System.out.println(ret);

        // 1. 获取 Pattern 对象
        //    由于Pattern类中只有一个构造方法,且是私有的,因此不能通过new的方式实例化对象
        //    需要使用 compile 方法,将一个正则表达式编译成 Pattern 对象
        Pattern pattern = Pattern.compile("\\d+");

        // 2. 将一个字符串进行切割
        String[] strs = pattern.split("hello121world123hello", 2);
        System.out.println(Arrays.toString(strs));

        // 3. 使用这个正则对象,和一个字符串进行比对校验
        //    校验结果,存储于 matcher 对象
        Matcher matcher = pattern.matcher("123hello456world789aaa012bbb");

        // 4. matches(): 对整个字符串进行校验,校验这个字符串是否和指定的正则规则相匹配
        // System.out.println(matcher.matches());

        // 5. find(): 对字符串中进行部分匹配
        //    group(): 返回单次匹配的字符串
        //    start(): 返回单次匹配的起点,闭
        //    end(): 返回单次匹配的终点,开
        while (matcher.find()) {
            System.out.print("匹配的字符串: " + matcher.group());
            System.out.printf("  范围:[%d, %d)\n", matcher.start(), matcher.end());
        }

        // 6. lookingAt : 始终从第一个字符匹配
        System.out.println(matcher.lookingAt() + ", " + matcher.group() +",start: " + matcher.start() + " end: " + matcher.end());
		Pattern pattern = Pattern.compile("(1\\d{2})(\\d{4})(\\d{4})");
        Matcher matcher = pattern.matcher("17788889999");
        System.out.println(matcher.groupCount());
        matcher.matches();
        String str = matcher.group(1);
        System.out.println(str);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值