1 字符串相关类
1.1 String
1.1.1 String对象简介
1.简介
- String类: 代表字符串。 Java 程序中的所有字符串字面值(如 “abc” )都作为此类的实例实现。
- String是一个final类,代表不可变的字符序列。
- 字符串是常量,用双引号引起来表示。 它们的值在创建之后不能更改。
- String对象的字符内容是存储在一个字符数组value[ ]中的。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
}
2.对象的创建
String str = "hello";
//本质上this.value = new char[0];
String s1 = new String();
//this.value = original.value;
String s2 = new String(String original);
//this.value = Arrays.copyOf(value, value.length);
String s3 = new String(char[] a);
String s4 = new String(char[] a,int startIndex,int count);
1.1.2 String对象的内存结构
1.基本结构
2. 产生String不同方式的内存结构
3.案例1
4.案例2
1.1.3 字符串拼接
案例1:
- 常量与常量的拼接结果在常量池。 且常量池中不会存在相同内容的常量。
- 只要其中有一个是变量, 结果就在堆中
- 如果拼接的结果调用intern()方法, 返回值就在常量池中
- String s1 = “a”; 说明:在字符串常量池中创建了一个字面量为"a"的字符串。
- s1 = s1 + “b”; 说明:实际上原来的“a”字符串对象已经丢弃了, 现在在堆空间中产生了一个字符串
- s1+“b”(也就是"ab")。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能。
- String s2 = “ab”; 说明:直接在字符串常量池中创建一个字面量为"ab"的字符串。
- String s3 = “a” + “b”; 说明: s3指向字符串常量池中已经创建的"ab"的字符串。
- String s4 = s1.intern(); 说明:堆空间的s1对象在调用intern()之后,会将常量池中已经存在的"ab"字符串赋值给s4。
案例2:
1.1.4 常用方法
- int length(): 返回字符串的长度: return value.length
- char charAt(int index): 返回某索引处的字符return value[index]
- boolean isEmpty(): 判断是否是空字符串: return value.length == 0
- String toLowerCase(): 使用默认语言环境, 将 String 中的所有字符转换为小写
- String toUpperCase(): 使用默认语言环境, 将 String 中的所有字符转换为大写
- String trim(): 返回字符串的副本, 忽略前导空白和尾部空白
- boolean equals(Object obj): 比较字符串的内容是否相同
- boolean equalsIgnoreCase(String anotherString): 与equals方法类似, 忽略大小写
- String concat(String str): 将指定字符串连接到此字符串的结尾。 等价于用“+”
- int compareTo(String anotherString): 比较两个字符串的大小
- String substring(int beginIndex): 返回一个新的字符串, 它是此字符串的从beginIndex开始截取到最后的一个子字符串。
- String substring(int beginIndex, int endIndex) : 返回一个新字符串, 它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。
- boolean contains(CharSequence s): 当且仅当此字符串包含指定的 char 值序列时,返回 true
- int indexOf(String str): 返回指定子字符串在此字符串中第一次出现处的索引
- int indexOf(String str, int fromIndex): 返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始
- int lastIndexOf(String str): 返回指定子字符串在此字符串中最右边出现处的索引
- int lastIndexOf(String str, int fromIndex): 返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索注: indexOf和lastIndexOf方法如果未找到都是返回-1
- boolean endsWith(String suffix): 测试此字符串是否以指定的后缀结束
- boolean startsWith(String prefix): 测试此字符串是否以指定的前缀开始
- boolean startsWith(String prefix, int toffset): 测试此字符串从指定索引开始的子字符串是否以指定前缀开始
- String replace(char oldChar, char newChar): 返回一个新的字符串, 它是通过用 newChar替换此字符串中出现的所有 oldChar 得到的。
- String replace(CharSequence target, CharSequence replacement): 使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。
- String replaceAll(String regex, String replacement) : 使 用 给 定 的replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
- String replaceFirst(String regex, String replacement) : 使 用 给 定 的replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
- boolean matches(String regex): 告知此字符串是否匹配给定的正则表达式。
- String[] split(String regex): 根据给定正则表达式的匹配拆分此字符串。
- String[] split(String regex, int limit): 根据匹配给定的正则表达式来拆分此字符串, 最多不超过limit个, 如果超过了, 剩下的全部都放到最后一个元素中。
示例:
@Test
public void test4() {
// 定义一个字符串对象
String s = "helloworld";
// int length():获取字符串的长度。
System.out.println("s.length:" + s.length());
System.out.println("----------------------");
// char charAt(int index):获取指定索引位置的字符
System.out.println("charAt:" + s.charAt(0));
System.out.println("----------------------");
// int indexOf(int ch):返回指定字符在此字符串中第一次出现处的索引。
System.out.println("indexOf:" + s.indexOf('l'));
System.out.println("----------------------");
// int indexOf(String str):返回指定字符串在此字符串中第一次出现处的索引。
System.out.println("indexOf:" + s.indexOf("owo"));
System.out.println("----------------------");
// int indexOf(int ch,int fromIndex):返回指定字符在此字符串中从指定位置后第一次出现处的索引。
System.out.println("indexOf:" + s.indexOf('l', 4));
System.out.println("indexOf:" + s.indexOf('k', 4)); // -1
System.out.println("indexOf:" + s.indexOf('l', 40)); // -1
System.out.println("----------------------");
// String substring(int start):从指定位置开始截取字符串,默认到末尾。包含start这个索引
System.out.println("substring:" + s.substring(5));
System.out.println("substring:" + s.substring(5,7)); //开始时5,结束是7,不包括7
System.out.println("substring:" + s.substring(0));
System.out.println("----------------------");
// String substring(int start,int end):从指定位置开始到指定位置结束截取字符串。包括start索引但是不包end索引
System.out.println("substring:" + s.substring(3, 8));
System.out.println("substring:" + s.substring(0, s.length()));
String s3 = " abc 123 ";
System.out.println(s3.trim().length()); //去掉前后两端的空格
//String[] split(String regex): 根据给定正则表达式的匹配拆分此字符串。
String s4 = "a,b,c,d,e,123";
String[] s5 = s4.split(",");
for (int i = 0; i < s5.length; i++) {
System.out.println(s5[i]);
}
}
1.2 StringBuffer和StringBuilder
StringBuilder 和 StringBuffer 非常类似,均代表可变的字符序列, 而且提供相关功能的方法也一样。
StringBuffer:
- StringBuffer 是线程安全的,所有的方法都被 synchronized 修饰,因此适用于多线程环境。
- 由于线程安全的特性,StringBuffer 的执行效率相对较低,特别是在高并发环境下。
- 在 Java 早期引入,用于字符串操作的类,是一个可变的、可修改的字符序列。
StringBuilder:
- StringBuilder 是非线程安全的,没有 synchronized 修饰,因此在单线程环境或者在已经保证线程安全的情况下使用。
- 由于没有线程安全的开销,StringBuilder 的执行效率相对较高,特别是在单线程环境下。
- 在 Java 5 引入,同样用于字符串操作,也是一个可变的、可修改的字符序列。
- 常用方法
- StringBuffer append(xxx):提供了很多的append()方法, 用于进行字符串拼接
- StringBuffer delete(int start,int end):删除指定位置的内容
- StringBuffer replace(int start, int end, String str):把[start,end)位置替换为str
- StringBuffer insert(int offset, xxx):在指定位置插入xxx
- StringBuffer reverse() :把当前字符序列逆转 public int indexOf(String str)
- public String substring(int start,int end):返回一个新的 String ,其中包含当前包含在此序列中的字符的子序列。
- public char charAt(int n ):返回指定索引处的此序列中的 char值。
- public void setCharAt(int n ,char ch) :指定索引处的字符设置为 ch 。
- 面试题
对比String、 StringBuffer、 StringBuilder
- String(JDK1.0): 不可变字符序列 final value[]
- StringBuffer(JDK1.0): 可变字符序列、效率低、线程安全
- StringBuilder(JDK 5.0):可变字符序列、效率高、 线程不安全
注意:作为参数传递的话,方法内部String不会改变其值, StringBuffer和StringBuilder会改 变其值。
三者性能对比
public class Test {
/**
* String:2031ms
*/
@Test
public void test1() {
String text = "";
long t1 = System.currentTimeMillis(); //时间戳:1970.1.1.0.0.0.0到现在的毫秒数
for (int i = 0; i < 20000; i++) {
text = text + i;
}
long t2 = System.currentTimeMillis();
System.out.println(t2 - t1);
}
/**
* StringBuffer:15ms
*/
@Test
public void test2() {
StringBuffer sb = new StringBuffer();
long t1 = System.currentTimeMillis(); //时间戳:1970.1.1.0.0.0.0到现在的毫秒数
for (int i = 0; i < 20000; i++) {
sb.append(i);
}
long t2 = System.currentTimeMillis();
System.out.println(t2 - t1);
}
/**
* StringBuilder:3ms
*/
@Test
public void test3() {
StringBuilder sb = new StringBuilder();
long t1 = System.currentTimeMillis(); //时间戳:1970.1.1.0.0.0.0到现在的毫秒数
for (int i = 0; i < 20000; i++) {
sb.append(i);
}
long t2 = System.currentTimeMillis();
System.out.println(t2 - t1);
}
}
2 日期相关类
System.currentTimeMillis():时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数
2.1 JDK8之前的日期类
2.1.1 Date
表示特定的瞬间,精确到毫秒
构造器:
- Date(): 使用无参构造器创建的对象可以获取本地当前时间。
- Date(long date)
常用方法
- getTime():返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。
- toString():把此 Date 对象转换为以下形式的 String: dow mon dd hh:mm:ss zzz yyyy 其
中: dow 是一周中的某一天 (Sun, Mon, Tue,Wed, Thu, Fri, Sat), zzz是时间标准。其它很多方法都过时了。
示例:
@Test
public void test1() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
//创建时间,方式1
Date date = new Date(); //当前时间
System.out.println(sdf.format(date));
//方式2
Date date1 = new Date(100);
System.out.println(sdf.format(date1)); //注意时区 1970.1.1 8:0:0.0.100
//得到时间戳
System.out.println(date.getTime());
System.out.println(date1.getTime());
}
2.1.2 SimpleDateFormat
SimpleDateFormat 是 Java 提供的一个用于日期格式化和解析的类,可以将日期对象转换为指定格式的字符串,以及将字符串解析为日期对象。
格式化:
- SimpleDateFormat() :默认的模式和语言环境创建对象
- public SimpleDateFormat(String pattern): 该构造方法可以用参数pattern指定的格式创建一个对象
- public String format(Date date): 方法格式化时间对象date
解析:
- public Date parse(String source): 从给定字符串的开始解析文本,以生成一个日期。
示例:
public class SimpleDateFormatExample {
public static void main(String[] args) throws ParseException {
// 创建 SimpleDateFormat 对象,指定日期格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 格式化日期为字符串
Date currentDate = new Date();
String formattedDate = sdf.format(currentDate);
System.out.println("格式化时间: " + formattedDate);
// 将字符串解析为日期
String dateString = "2023-07-25 15:30:00";
Date parsedDate = sdf.parse(dateString);
System.out.println("解析时间: " + parsedDate);
}
}
2.1.3 Calander
Calendar是一个抽象基类,主用用于完成日期字段之间相互操作的功能。
获取Calendar实例的方法
- 使用Calendar.getInstance()方法
- 调用它的子类GregorianCalendar的构造器。
一个Calendar的实例是系统时间的抽象表示,通过get(int field)方法来取得想要的时间信息。Calendar 类提供了许多常用的方法来获取和设置日期时间字段:
- public void set(int field,int value)
- public void add(int field,int amount)
- public final Date getTime()
- public final void setTime(Date date)
注意:
获取月份时: 一月是0,二月是1,…, 12月是11
获取星期时: 周日是1,周一是2 ,…,周六是7
示例:
@Test
public void test3() throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//获取默认时区的 Calendar 实例
Calendar c = Calendar.getInstance();
//得到field
System.out.println(c.get(Calendar.YEAR)); //得到年
System.out.println(c.get(Calendar.MONTH)); //得到月 传统日期月从0开始,周从周日=1开始
System.out.println(c.get(Calendar.DAY_OF_MONTH));
System.out.println(c.get(Calendar.HOUR_OF_DAY));
//设置field
c.set(Calendar.MONTH, 0); //传统日期月从0开始
System.out.println(sdf.format(c.getTime()));//得到date
//减3个月
c.add(Calendar.MONTH, -3);
System.out.println(sdf.format(c.getTime()));//得到date
//创建1970-1-1 8:0:0.0时间
//方式1:
String dateStr = "1970-01-1 08:0:0.0";
//把字符串解析成日期,string->date
Date date1 = sdf.parse(dateStr);
System.out.println(date1.getTime());
//方式2
Calendar c2 = Calendar.getInstance();
c2.set(1970, 0, 1,8,0);
c2.set(Calendar.MILLISECOND, 0);
System.out.println(sdf.format(c2.getTime()));
//当前时间的4周后
Calendar c3 = Calendar.getInstance(); //当前时间
c3.add(Calendar.WEEK_OF_YEAR, 5);
System.out.println(sdf.format(c3.getTime()));
}
2.2 JDK8新日期API
Java 8中引入的java.time API 已经纠正了过去的缺陷,将来很长一段时间内它都会为我们服务。Java 8 吸收了 Joda-Time 的精华,以一个新的开始为 Java 创建优秀的 API。新的 java.time 中包含了所有关于本地日期(LocalDate)、本地时间(LocalTime)、本地日期时间(LocalDateTime)、时区(ZonedDateTime)和持续时间(Duration)的类。历史悠久的 Date 类新增了 toInstant() 方法,用于把 Date 转换成新的表示形式。这些新增的本地化时间日期 API 大大简化了日期时间和本地化的管理。
2.2.1 LocalDate、 LocalTime、 LocalDateTime
LocalDate、 LocalTime、 LocalDateTime 类是其中较重要的几个类,它们的实例是不可变的对象,分别表示使用 ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的本地日期或时间,并不包含当前的时间信息,也不包含与时区相关的信息。
- LocalDate代表IOS格式(yyyy-MM-dd)的日期,可以存储生日、纪念日等日期。
- LocalTime表示一个时间,而不是日期。
- LocalDateTime是用来表示日期和时间的, 这是一个最常用的类之一。
注: ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法,也就是公历。
2.2.2 Instant
- Instant:时间线上的一个瞬时点。 这可能被用来记录应用程序中的事件时间戳。
- 在处理时间和日期的时候,我们通常会想到年,月,日,时,分,秒。然而,这只是时间的一个模型,是面向人类的。第二种通用模型是面向机器的,或者说是连续的。在此模型中,时间线中的一个点表示为一个很大的数,这有利于计算机处理。 在UNIX中,这个数从1970年开始,以秒为的单位;同样的,在Java中,也是从1970年开始,但以毫秒为单位。
- java.time包通过值类型Instant提供机器视图,不提供处理人类意义上的时间单位。 Instant表示时间线上的一点,而不需要任何上下文信息,例如,时区。概念上讲, 它只是简单的表示自1970年1月1日0时0分0秒( UTC)开始的秒数。 因为java.time包是基于纳秒计算的,所以Instant的精度可以达到纳秒级。
- 1秒 = 1000毫秒 =10^6微秒 =10^9纳秒
方法 | 描述 |
---|---|
now() | 静态方法, 返回默认UTC时区的Instant类的对象 |
ofEpochMilli(long epochMilli) | 静态方法数之后的,Instant 返回在类的对象 1970-01-01 00:00:00基础上加上指定毫秒 |
atOffset(ZoneOffset offset) | 结合即时的偏移来创建一个 OffsetDateTime |
toEpochMilli() | 返回1970-01-01 00:00:00到当前时间的毫秒数, 即为时间戳 |
2.2.3 DateTimeFormatter
java.time.format.DateTimeFormatter 类:该类提供了三种格式化方法:
- 预定义的标准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
- 本地化相关的格式。如: ofLocalizedDateTime(FormatStyle.LONG)
- 自定义的格式。如: ofPattern(“yyyy-MM-dd hh:mm:ss”)
方 法 | 描 述 |
---|---|
ofPattern(String pattern) | 静态方法 , 返回一个指定字符串格式的 DateTimeFormatter |
format(TemporalAccessor t) | 格式化一个日期、 时间, 返回字符串 |
parse(CharSequence text) | 将指定格式的字符序列解析为一个日期、 时间 |
示例:
@Test
public void test() throws ParseException {
//得到当前时间
//LocalDateTime:(UTC)日期时间,理解成Date + Calander
//LocalDate:日期
//LocalTime:时间
LocalDateTime l1 = LocalDateTime.now();
System.out.println("l1 = " + l1);
//得到field
System.out.println(l1.getMonth().getValue()); //新时间api,月从1开始
System.out.println(l1.getYear());
System.out.println(l1.get(ChronoField.HOUR_OF_DAY)); //时
//设置field,支持chain方法链,设置1月1日
LocalDateTime l2 = l1.withMonth(1).withDayOfMonth(1);
System.out.println(l2);
//加3个月,加3周
LocalDateTime l3 = l2.plusMonths(3).plusWeeks(3);
System.out.println(l3);
//减3月
LocalDateTime l4 = l3.minusMonths(3);
System.out.println(l4);
//创建1970-1-1 8:0:0.0时间
LocalDateTime l5 = LocalDateTime.of(1970, 1, 1, 0, 0, 0, 0);
System.out.println(l5);
//时间戳操作 Instant
Instant i1 = l5.toInstant(ZoneOffset.UTC); //得到utc时间的Instant
System.out.println(i1.toEpochMilli());
LocalDateTime l6 = LocalDateTime.of(1970, 1, 1, 8, 0, 0, 0);
Instant i2 = l6.toInstant(ZoneOffset.ofHours(8)); //得到东8区的Instant
System.out.println(i2.toEpochMilli()); //utc时间的1970.1.1.0点,北京时间的8点,是时间戳的0
//格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日HH时mm分ss秒.SSS");
System.out.println(formatter.format(LocalDateTime.now()));
}
3 System和Runtime类
3.1 System类
- System类代表系统,系统级的很多属性和控制方法都放置在该类的内部。该类位于java.lang包。
- 由于该类的构造器是private的,所以无法创建该类的对象,也就是无法实例化该类。其内部的成员变量和成员方法都是static的, 所以也可以很方便的进行调用。
- 成员变量
System类内部包含in、 out和err三个成员变量,分别代表标准输入流(键盘输入),标准输出
流(显示器)和标准错误输出流(显示器)。 - 成员方法
native long currentTimeMillis():该方法的作用是返回当前的计算机时间,时间的表达格式
为当前计算机时间和GMT时间(格林威治时间)1970年1月1号0时0分0秒所差的毫秒数。
void exit(int status):该方法的作用是退出程序。其中status的值为0代表正常退出,非零代
表异常退出。 使用该方法可以在图形界面编程中实现程序的退出功能等。
void gc():该方法的作用是请求系统进行垃圾回收。至于系统是否立刻回收,则取决于系统中
垃圾回收算法的实现以及系统执行时的情况。
String getProperty(String key):该方法的作用是获得系统中属性名为key的属性对应的值。
3.2 Runtime类
- public void addShutdownHook(Thread hook):捕获jvm退出时间
示例:
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
System.out.println("捕获了jvm退出--释放资源");
}
}));
System.out.println("abc");
System.out.println("123");
// int i = 1 / 0;
System.out.println("abc");
System.out.println("123");
System.out.println("-------------------");
}
结果:
abc
123
abc
123
-------------------
捕获了jvm退出--释放资源
Process finished with exit code 0
4 BigInteger和BigDecimal类
4.1 BigInteger类
- Integer类作为int的包装类,能存储的最大整型值为231-1, Long类也是有限的,最大为263-1。如果要表示再大的整数,不管是基本数据类型还是他们的包装类都无能为力,更不用说进行运算了。
- java.math包的BigInteger可以表示不可变的任意精度的整数。 BigInteger 提供所有 Java 的基本整
数操作符的对应物,并提供java.lang.Math 的所有相关方法。另外, BigInteger 还提供以下运算:模算术、 GCD 计算、质数测试、素数生成、位操作以及一些其他操作。 - 构造器 BigInteger(String val): 根据字符串构建BigInteger对象
- 常用方法
public BigInteger abs():返回此 BigInteger 的绝对值的 BigInteger。
BigInteger add(BigInteger val) :返回其值为 (this + val) 的 BigInteger
BigInteger subtract(BigInteger val) :返回其值为 (this - val) 的 BigInteger
BigInteger multiply(BigInteger val) :返回其值为 (this * val) 的 BigInteger
BigInteger divide(BigInteger val) :返回其值为 (this / val) 的 BigInteger。整数相除只保留整数部分。
BigInteger remainder(BigInteger val) :返回其值为 (this % val) 的 BigInteger。
BigInteger[] divideAndRemainder(BigInteger val):返回包含 (this / val) 后跟(this % val) 的两个 BigInteger 的数组。
BigInteger pow(int exponent) :返回其值为 (thisexponent) 的 BigInteger。
示例:
@Test
public void test1() {
System.out.println(Integer.MAX_VALUE);
Integer i1 = 2147483647;
//Integer i2 = 2147483648;
BigInteger i3= new BigInteger("10");
System.out.println(i3);
BigInteger i4 = new BigInteger("15");
BigInteger i5 = i3.add(i4);
System.out.println(i5);
BigInteger[] arrs = i3.divideAndRemainder(new BigInteger("3"));
System.out.println(Arrays.toString(arrs));
}
结果:
2147483647
10
25
[3, 1]
4.2 BigDecimal类
- 一般的Float类和Double类可以用来做科学计算或工程计算,但在商业计算中,要求数字精度比较高,故用到java.math.BigDecimal类。
- BigDecimal类支持不可变的、任意精度的有符号十进制定点数。
- 构造器
public BigDecimal(double val)
public BigDecimal(String val) - 常用方法
public BigDecimal add(BigDecimal augend)
public BigDecimal subtract(BigDecimal subtrahend)
public BigDecimal multiply(BigDecimal multiplicand)
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
5 正则表达式
正则表达式,又称规则表达式,(Regular Expression,在代码中常简写为regex、regexp或RE),是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为"元字符"),是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串,通常被用来检索、替换那些符合某个模式(规则)的文本。简单来说,正则表达式就是一个很牛逼的字符串处理工具。
正则表达式在线工具 : https://c.runoob.com/front-end/854/?optionGlobl=global
5.1 String类中的正则表达式
matches(String regex):判断字符串是否与给定的正则表达式匹配。
String text = "Hello, World!";
boolean isMatch = text.matches("He.*");
System.out.println(isMatch); //true
split(String regex):根据正则表达式将字符串分割成字符串数组。
String text = "apple,banana,grape";
String[] fruits = text.split(",");
for (String fruit : fruits) {
System.out.println(fruit);
}
输出:
apple
banana
grape
replaceAll(String regex, String replacement):使用给定的替换字符串替换所有匹配的子字符串。
String text = "Java is fun and Java is cool.";
String newText = text.replaceAll("Java", "Python");
System.out.println(newText);
输出:
Python is fun and Python is cool.
replaceFirst(String regex, String replacement):使用给定的替换字符串替换第一个匹配的子字符串。
String text = "Java is fun and Java is cool.";
String newText = text.replaceFirst("Java", "Python");
System.out.println(newText);
输出:
Python is fun and Java is cool.
5.2 正则表达式常用类
5.2.1 Pattern类
pattern 对象是一个正则表达式的编译表示。Pattern 类没有公共构造方法。要创建一个 Pattern 对象,你必须首先调用其公共静态编译方法,它返回一个 Pattern 对象。该方法接受一个正则表达式作为它的第一个参数。
- compile():通过正则得到一个Pattern
- matchers():方便正则表达式只是用一次,进行匹配
- matcher():产生Matcher对象,多次正则匹配推荐使用
@Test
public void test1(){
System.out.println(Pattern.matches("^[0-9]{5,12}$","837541653"));
System.out.println(Pattern.matches("^[0-9]{5,12}$","8375416"));
System.out.println(Pattern.matches("^[0-9]{5,12}$","8375653"));
Pattern pattern = Pattern.compile("^[0-9]{5,12}$");
System.out.println(pattern.matcher("837541653").matches());
pattern.matcher("8375416").matches();
pattern.matcher("8375653").matches();
}
5.2.2 Matcher类
Matcher 对象是对输入字符串进行解释和匹配操作的引擎。与Pattern 类一样,Matcher 也没有公共构造方法。你需要调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。
1.索引方法
索引方法提供了有用的索引值,精确表明输入字符串中在哪能找到匹配:
- public int start():返回以前匹配的初始索引。
- public int start(int group): 返回在以前的匹配操作期间,由给定组所捕获的子序列的初始索引
- public int end():返回最后匹配字符之后的偏移量。
- public int end(int group):返回在以前的匹配操作期间,由给定组所捕获子序列的最后字符之后的偏移量。
示例:
@Test
public void test6(){
String text = "Java is fun and Java is cool.";
String patternString = "Java";
Pattern pattern = Pattern.compile(patternString);
Matcher matcher = pattern.matcher(text);
// find() 方法查找下一个匹配的子串
while (matcher.find()) {
int start = matcher.start(); // 获取匹配的子串起始位置索引
int end = matcher.end(); // 获取匹配的子串结束位置索引(不包括)
String match = matcher.group(); // 获取匹配的子串
System.out.println("Match: " + match);
System.out.println("Start Index: " + start);
System.out.println("End Index: " + end);
}
}
结果:
匹配: Java
开始索引: 0
结束索引: 4
匹配: Java
开始索引: 16
结束索引: 20
2.查找方法
查找方法用来检查输入字符串并返回一个布尔值,表示是否找到该模式:
- public boolean lookingAt():尝试将从区域开头开始的输入序列与该模式匹配。
- public boolean find():尝试查找与该模式匹配的输入序列的下一个子序列。
- public boolean find(int start):重置此匹配器,然后尝试查找匹配该模式、从指定索引开始的输入序列的下一个子序列。
- public boolean matches():尝试将整个区域与模式匹配。
- group():返回上一个匹配项匹配的输入子序列。
- group(int group):返回上一个匹配操作期间给定组捕获的输入子序列。
3.替换方法
替换方法是替换输入字符串里文本的方法:
- public Matcher appendReplacement(StringBuffer sb, String replacement):实现非终端添加和替换步骤。
- public StringBuffer appendTail(StringBuffer sb):实现终端添加和替换步骤。
- public String replaceAll(String replacement):替换模式与给定替换字符串相匹配的输入序列的每个子序列。
- public String replaceFirst(String replacement):替换模式与给定替换字符串匹配的输入序列的第一个子序列。
- public static String quoteReplacement(String s):返回指定字符串的字面替换字符串。这个方法返回一个字符串,就像传递给Matcher类的appendReplacement 方法一个字面字符串一样工作。
示例:
@Test
public void test() {
String content =
"Java 是由 Sun Microsystems 公司于 1995 年 5 月推出的高级程序设计语言。\n"
+ "Java 可运行于多个平台,如 windows,Mac OS 及其他多种 UNIX 版本的系统。\n"
+ "本教程通过简单的实例将让大家更好的了解 Java 编程语言。\n"
+ "移动操作系统 Android 大部分的代码采用 Java 编程语言编程。";
//创建一个Pattern对象
Pattern pattern = Pattern.compile("Java");
//创建一个匹配对象
Matcher matcher = pattern.matcher(content);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
//将Java替换为java后,将最后匹配到之前的子串都添加到sb对象中
matcher.appendReplacement(sb, "java");
System.out.println("sb:" + sb);
System.out.println("---------分割线-----------");
}
//将最后匹配到的子串添加到sb中
matcher.appendTail(sb);
System.out.println("sb: " + sb);
}
结果:
sb:java
---------分割线-----------
sb:java 是由 Sun Microsystems 公司于 1995 年 5 月推出的高级程序设计语言。
java
---------分割线-----------
sb:java 是由 Sun Microsystems 公司于 1995 年 5 月推出的高级程序设计语言。
java 可运行于多个平台,如 windows,Mac OS 及其他多种 UNIX 版本的系统。
本教程通过简单的实例将让大家更好的了解 java
---------分割线-----------
sb:java 是由 Sun Microsystems 公司于 1995 年 5 月推出的高级程序设计语言。
java 可运行于多个平台,如 windows,Mac OS 及其他多种 UNIX 版本的系统。
本教程通过简单的实例将让大家更好的了解 java 编程语言。
移动操作系统 Android 大部分的代码采用 java
---------分割线-----------
sb: java 是由 Sun Microsystems 公司于 1995 年 5 月推出的高级程序设计语言。
java 可运行于多个平台,如 windows,Mac OS 及其他多种 UNIX 版本的系统。
本教程通过简单的实例将让大家更好的了解 java 编程语言。
移动操作系统 Android 大部分的代码采用 java 编程语言编程。
5.3 正则表达式的语法
5.3.1 正则转义符
元符号-转义号 \\
\\ 符号说明:在我们使用正则表达式去检索某些特殊字符的时候,需要用到转义字符,否则检测不到结果,甚至会报错。
需要用到转义符的字符有:. * + ( )$ / \ ? [ ] ^ { }
注意:在Java的正则表达式中,两个 \\ 代表其他语言中的一个 \
5.3.2 正则表达式支持字符
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之外的任何单字符。要匹配.字符本身,请使用. |
** | 用于转义下一个字符,或指定八进制、十六进制字符。如果需匹配\字符,请用\\ |
丨 | 指定两项之间任选一项。如果要匹配丨字符本身,请使用\丨 |
3.预定义字符
预定义字符 | 说明 |
---|---|
. | 可以匹配任何字符 |
\d | 匹配 0~9 的所有数字 |
\D | 匹配非数字 |
\s | 匹配所有的空白字符,包括空格、制表符、回车符、换页符、换行符等 |
\S | 匹配所有的非空白字符 |
\w | 匹配所有的单词字符,包括 0~9 所有数字、26 个英文字母和下画线_ |
\W | 匹配所有的非单词字符 |
4.方括号表达式
表示枚举 :例如 [abc]表示 a、b、c 其中任意一个字符; [gz]表示 g、z 其中任意一个字符
表示范围: 例如 [a-f]表示 a~f 范围内的任意字符; [\u0041-\u0056]表示十六进制字符 \u0041 到 \u0056 范围的字符。
范围可以和枚举结合使用,如 [a-cx-z],表示 a ~ c、x ~ z 范围内的任意字符
表示求否:^ ,例如 [^abc]表示非 a、b、c 的任意字符; [^a-f]表示不是 a~f 范围内的任意字符
表示“与”运算:&&, 例如 [a-z&&[def]]是 a~z 和 [def] 的交集,表示 d、ef[a-z&&^bc]]是 a~z 范围内的所有字符,除 b 和 c 之外[ad-z] [a-z&&[m-p]]是 a~z 范围内的所有字符,除 m~p 范围之外的字符 表示“并”运算 并运算与前面的枚举类似。例如 [a-d[m-p]]表示 [a-dm-p]
补充:
Java正则表达式默认是区分字母大小写的,如要实现不区分大小写
(?i)abc表示abc都不区分大小写
a(?i)bc表示bc不区分大小写
a((?i)b)c表示只有b不区分大小写
Pattern pattern=Pattern.compile(regStr,Pattern.CASE_INSENSITIVE);
//当创建Pattern对象时,指定Pattern.CASE_INSENSITIVE,表示匹配不区分字母大小写
Java匹配默认贪婪匹配,即尽可能匹配多的,比如"a{3,4}“,表示匹配aaa或者aaaa,但是优先匹配aaaa,例如原字符串中包括"aaaaaa”,匹配"a{3,4}“时,会找到"aaaa”
5.3.3 捕获组(capture group)
从正则表达式左侧开始,每出现一个左括号"("记做一个分组,分组编号从 1 开始。0 代表整个表达式。
常用分组构造形式(pattern)
对于时间字符串:2017-04-25,表达式为:(\d{4})-((\d{2})-(\d{2}))
有 4 个左括号,所以有 4 个分组:
编号 | 捕获组 | 匹配 |
---|---|---|
0 | (\d{4})-((\d{2})-(\d{2})) | 2017-04-25 |
1 | (\d{4}) | 2017 |
2 | ((\d{2})-(\d{2})) | 04-25 |
3 | (\d{2}) | 04 |
4 | (\d{2}) | 25 |
5.4 正则表达式的常见应用
- 验证字符串是否全是汉字
Pattern pattern=Pattern.compile(“^ [\u0391-\uffe5]+$”); - 验证字符串是否是邮编
Pattern pattern=Pattern.compile(“^\d{6}$”); - 验证字符串是否是QQ号码
Pattern pattern=Pattern.compile(“^ [1-9]d{4,9}$”); - 验证字符串是否是手机号码(要求:必须以13,14,15,18,19开头的11位数)
Pattern pattern=Pattern.compile(“^1[3|4|5|8|9]\d{9}$”); - 验证字符串是否是url
Pattern pattern=Pattern.compile(“^((http|https) : //)([\\w-]+\\.)+[\\w-]+(\\/[\\w-?=&/%.#]*)?$”);