java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java正则表达式与日期时间

Java常用API之正则表达式与日期时间操作完全攻略

作者:密云迷晚岫

大家都知道在java开发中,正则表达式是处理字符串匹配,验证和提取的强大工具,这篇文章主要介绍了Java常用API之正则表达式与日期时间操作的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

引言

在日常Java开发中,处理字符串匹配和日期时间操作是两大高频需求。无论是验证用户输入的手机号、邮箱格式,还是记录系统日志时间、计算日期间隔,都离不开强大的正则表达式和日期时间API。本文将带你深入掌握Java中的正则表达式、Date、DateFormat及Calendar四大核心类,让你的开发效率翻倍!

一、正则表达式:字符串匹配的利器

1.1 什么是正则表达式?

正则表达式(Regular Expression)是一个用于描述字符串匹配规则的强大工具。它使用单个字符串来定义匹配模式,能够高效地进行字符串的检索、替换和验证操作。在Java中,正则表达式的规则定义主要在java.util.regex.Pattern类中。

核心特点:明确区分大小写、灵活组合规则、支持复杂模式匹配

1.2 基础匹配规则详解

1.2.1 单个字符匹配

语法含义示例
x代表字符x"a" 匹配字符串"a"
\\代表反斜线\"\\" 匹配单个""
\t制表符产生制表空间
\n换行符光标移到下一行
\r回车符光标移到下一行行首

1.2.2 字符类匹配

[abc]       // 匹配a、b或c中的任意一个字符
[^abc]      // 匹配除a、b、c之外的任意字符
[a-zA-Z]    // 匹配任意英文字母(大小写)
[0-9]       // 匹配任意数字
[a-zA-Z_0-9] // 匹配字母、数字或下划线(单词字符)

1.2.3 预定义字符类

.           // 匹配任意字符(若想匹配"."本身,需用"\\.")
\d          // 等价于[0-9],匹配数字
\w          // 等价于[a-zA-Z_0-9],匹配单词字符

1.2.4 边界匹配器

^           // 匹配行的开头
$           // 匹配行的结尾
\b          // 匹配单词边界

示例^[abc][0-9]$ 表示字符串必须以a、b或c开头,以数字结尾,且只能有两个字符。

1.2.5 数量词

X?          // X出现0次或1次
X*          // X出现0次或多次
X+          // X出现1次或多次
X{n}        // X恰好出现n次
X{n,}       // X至少出现n次
X{n,m}      // X出现n到m次

1.3 实战练习:经典匹配场景

练习1:匹配数字字符串

规则:"[0-9]{6,12}"
描述:匹配长度为6-12位的纯数字
验证

String regex = "[0-9]{6,12}";
System.out.println("123456789".matches(regex)); // true
System.out.println("12345".matches(regex));     // false

练习2:验证手机号码

规则:"1[34578][0-9]{9}"
描述:11位手机号,第1位为1,第2位为3/4/5/7/8,后9位为任意数字
验证

String regex = "1[34578][0-9]{9}";
System.out.println("13312345678".matches(regex)); // true
System.out.println("12345678901".matches(regex)); // false

练习3:匹配特定模式

规则:"a*b"
描述:在零个或多个a后面必须有一个b,且b为最后一个字符
验证

String regex = "a*b";
System.out.println("aaaaab".matches(regex)); // true
System.out.println("abc".matches(regex));    // false

1.4 字符串类中的正则方法

1.4.1 matches() - 字符串验证

// 验证QQ号码:5-15位数字,且不能以0开头
String qq = "604154942";
String regex = "[1-9][0-9]{4,14}";
boolean isValid = qq.matches(regex);
System.out.println("QQ号码验证:" + isValid); // true

// 验证手机号
String phone = "18800022116";
String phoneRegex = "1[34578][0-9]{9}";
System.out.println("手机号验证:" + phone.matches(phoneRegex)); // true

1.4.2 split() - 字符串分割

// 按分隔符分割字符串
String s1 = "18-22-40-65";
String[] arr1 = s1.split("-");
System.out.println(Arrays.toString(arr1)); // [18, 22, 40, 65]

// 按空格分割
String s2 = "18 22 40 65";
String[] arr2 = s2.split(" ");
System.out.println(Arrays.toString(arr2)); // [18, 22, 40, 65]

1.4.3 replaceAll() - 内容替换

// 将字符串中的数字全部替换为*
String s = "Hello12345World6789012";
String regex = "[0-9]";
String result = s.replaceAll(regex, "*");
System.out.println(result); // Hello*****World******

1.5 综合练习:真实业务场景

场景1:匹配各类数字

// 匹配正整数
String posIntRegex = "\\d+";

// 匹配正小数
String posDecimalRegex = "\\d+\\.\\d+";

// 匹配保留两位小数的正数
String currencyRegex = "\\d+\\.\\d{2}";

场景2:验证邮箱格式

// 推荐正则
String emailRegex = "[a-zA-Z_0-9]+@[a-zA-Z_0-9]+(\\.[a-zA-Z_0-9]+)+";
// 或简化版
String emailRegex2 = "\\w+@\\w+(\\.\\w+)+";

System.out.println("test@example.com".matches(emailRegex)); // true

场景3:解析IP地址

String ip = "192.168.1.100";
String[] segments = ip.split("\\."); // 注意转义
System.out.println(Arrays.toString(segments)); // [192, 168, 1, 100]

二、Date类:时间戳的载体

2.1 Date类概述

java.util.Date类表示特定的瞬间,精确到毫秒。它封装了从1970年1月1日00:00:00 GMT以来的毫秒数。

// 创建当前时间的Date对象
Date now = new Date();
System.out.println(now); // 默认调用toString()

// 根据毫秒值创建Date对象
Date date = new Date(1607616000000L);
System.out.println(date); // Fri Dec 11 00:00:00 CST 2020

2.2 核心方法

// 获取当前时间的毫秒值(最常用)
long timeMillis = new Date().getTime();
System.out.println("当前毫秒值:" + timeMillis);

// 计算两天后的时间
Date twoDaysLater = new Date(System.currentTimeMillis() + 2 * 24 * 60 * 60 * 1000);
System.out.println("两天后:" + twoDaysLater);

注意:Date类中的许多方法(如getYear(), getMonth())已过时,推荐使用Calendar或DateFormat替代。

三、DateFormat类:格式化时间艺术

3.1 DateFormat类概述

DateFormat是日期/时间格式化的抽象类,它的子类SimpleDateFormat提供了强大的格式化与解析功能,支持日期与字符串之间的双向转换。

格式模板字母表

3.2 SimpleDateFormat实战

3.2.1 Date转String(格式化)

Date date = new Date(1607616000000L); // 2020-12-11

// 格式化为中文日期
DateFormat df1 = new SimpleDateFormat("yyyy年MM月dd日");
String str1 = df1.format(date);
System.out.println(str1); // 2020年12月11日

// 格式化为完整时间
DateFormat df2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str2 = df2.format(date);
System.out.println(str2); // 2020-12-11 00:00:00

3.2.2 String转Date(解析)

String str = "2020年12月11日";
DateFormat df = new SimpleDateFormat("yyyy年MM月dd日");
try {
    Date date = df.parse(str);
    System.out.println(date); // Fri Dec 11 00:00:00 CST 2020
} catch (ParseException e) {
    e.printStackTrace();
}

// 注意:格式必须完全匹配,否则会抛出ParseException

四、Calendar类:日历操作的集大成者

4.1 Calendar类概念

Calendar是日期字段操作的封装类,提供了比Date更强大的日期计算能力。它是一个抽象类,通过静态方法getInstance()获取实例。

// 获取当前日历对象
Calendar c = Calendar.getInstance();
System.out.println(c.getTime()); // 获取Date对象

4.2 核心操作方法

4.2.1 获取时间字段

Calendar c = Calendar.getInstance();

int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH) + 1; // 注意:月份从0开始!
int day = c.get(Calendar.DATE);
int hour = c.get(Calendar.HOUR_OF_DAY);
int minute = c.get(Calendar.MINUTE);
int second = c.get(Calendar.SECOND);

System.out.println("当前时间:" + year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second);

4.2.2 增减时间字段

Calendar c = Calendar.getInstance();

// 3天后
c.add(Calendar.DATE, 3);
System.out.println("3天后:" + c.getTime());

// 5小时后
c.add(Calendar.HOUR, 5);
System.out.println("再过5小时:" + c.getTime());

// 重置为当前时间
c = Calendar.getInstance();

4.2.3 设置指定日期

Calendar c = Calendar.getInstance();

// 设置为2020年5月20日
c.set(Calendar.YEAR, 2020);
c.set(Calendar.MONTH, 4); // 0=1月, 4=5月
c.set(Calendar.DATE, 20);
System.out.println("设定日期:" + c.getTime());

// 或使用set()的重载方法
c.set(2020, 4, 20); // 更简洁

4.2.4 Date与Calendar互转

// Calendar转Date
Calendar c = Calendar.getInstance();
Date date = c.getTime();

// Date转Calendar
Date date2 = new Date();
Calendar c2 = Calendar.getInstance();
c2.setTime(date2);

4.3 重要注意事项

  1. 星期起始:西方以周日为一周的开始,中国习惯周一,需特别注意
  2. 月份范围Calendar.MONTH的取值是0-11(1月=0,12月=11)**
  3. 日期比较:时间越靠后,毫秒值越大,Date对象也越大

五、综合实战案例

案例1:计算出生天数

public static int getDaysSinceBirth(int birthYear, int birthMonth, int birthDay) {
    // 获取当前时间
    Calendar now = Calendar.getInstance();
    
    // 设置出生日期
    Calendar birth = Calendar.getInstance();
    birth.set(Calendar.YEAR, birthYear);
    birth.set(Calendar.MONTH, birthMonth - 1); // 注意月份转换
    birth.set(Calendar.DATE, birthDay);
    
    // 获取天数并计算差值
    long nowDays = now.getTimeInMillis() / (24 * 60 * 60 * 1000);
    long birthDays = birth.getTimeInMillis() / (24 * 60 * 60 * 1000);
    
    return (int) (nowDays - birthDays);
}

// 使用示例
System.out.println("我已出生:" + getDaysSinceBirth(1995, 5, 10) + "天");

案例2:倒计时到指定日期

public static int daysUntil2025NewYear() {
    Calendar now = Calendar.getInstance();
    
    Calendar target = Calendar.getInstance();
    target.set(2025, 0, 1); // 2025年1月1日
    
    long diff = target.getTimeInMillis() - now.getTimeInMillis();
    return (int) (diff / (24 * 60 * 60 * 1000));
}

System.out.println("距离2025年元旦还有:" + daysUntil2025NewYear() + "天");

六、知识点总结与最佳实践

6.1 核心知识点回顾

类名主要作用关键方法
正则表达式字符串模式匹配matches(), split(), replaceAll()
Date表示时间戳getTime(), 构造方法
DateFormat日期格式化format(), parse()
Calendar日历字段操作get(), add(), set()

6.2 最佳实践建议

  1. 正则表达式

    • 对复杂正则务必注释说明
    • 使用+而不是*进行邮箱匹配,避免空用户名
    • 预编译Pattern提升性能(频繁使用时)
  2. 日期操作

    • 优先使用Calendar进行日期计算
    • 注意月份从0开始的陷阱,建议封装工具类
    • 多线程环境下,SimpleDateFormat需独立实例(线程不安全)
  3. 代码可读性

    • 将常用正则定义为常量
    • 封装日期工具类,隐藏Calendar复杂性

6.3 避坑指南

// 错误示例:月份未修正
Calendar c = Calendar.getInstance();
c.set(2020, 5, 1); // 实际设置为6月1日!

// 正确做法
c.set(2020, Calendar.JUNE, 1); // 使用常量
// 或
c.set(2020, 5 - 1, 1); // 明确注释

七、课后思考题

  1. 如何编写正则表达式匹配身份证号(18位,末尾可为X)?
  2. 使用Calendar实现一个方法,获取指定日期是星期几(中文)?
  3. 为什么说SimpleDateFormat是线程不安全的?如何解决?
  4. 计算两个日期之间的工作日天数(排除周末)?

结语

掌握正则表达式和日期时间API是Java开发者的基本功。本文通过大量实例,从基础语法到实战应用,全面解析了这四个核心类的使用技巧。建议读者动手实践每个案例,并根据业务需求封装自己的工具类,真正做到举一反三。

到此这篇关于Java常用API之正则表达式与日期时间操作完全攻略的文章就介绍到这了,更多相关Java正则表达式与日期时间内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文