四、正则表达式

正则表达式描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串、将匹配的子串做替换或者从某个串中取出符合某个条件的子串等。

1、快速入门

通过一个例子“只允许输入数字”,比较没有使用正则表达式和使用正则表达式的差异。

(1)只能输入数字

这里使用一个for循环和if判断结合起来,实现只允许输入数字的判断。

 

public void testNumber1() {
                   Stringstring = "124354232";
                   char[]charArray = string.toCharArray();
                   boolean isAllNumber= true;
                   for (int i =0; i < charArray.length; i++) {
                            if(!Character.isDigit(charArray[i])){
                                     isAllNumber=false;
                            }
                   }
                   if(isAllNumber){
                            System.out.println("全部是数字");
                   }else {
                            System.out.println("字符串中含有除数字以外的字符");
                   }
}

(2)使用正则表达式

使用正则表达式("[0-9]+"),可以很容易的实现同样的功能,代码要简洁的多。

public void testNumber2() {
         String string ="124354232";
         booleanisAllNumber  =string.matches("[0-9]+");
         System.out.println(isAllNumber);
}

2、正则表达式

正则表达式是由普通字符(例如字符a到z)以及特殊字符(称为"元字符")组成的文字模式,描述在搜索文本时要匹配的一个或多个字符串。

正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。

(1)字符表示


.

任何字符(与行结束符可能匹配也可能不匹配)

\d

数字:[0-9]

\D

非数字: [^0-9]

\s

空白字符:[ \t\n\x0B\f\r]

\S

非空白字符:[^\s]

\w

单词字符:[a-zA-Z_0-9]

\W

非单词字符:[^\w]


 

public boolean matches(String regex)此字符串是否匹配给定的正则表达式。

 

例子:

         System.out.println("a".matches("."));

         System.out.println("1".matches("\\d"));

         System.out.println("%".matches("\\D"));

         System.out.println("\r".matches("\\s"));

         System.out.println("^".matches("\\S"));

         System.out.println("a".matches("\\w"));

         System.out.println("^".matches("\\W"));               

(2)数量


X?

X出现一次或一次也没有

X*

X普通字符出现零次或多次

X+

X普通字符一次或多次

X{n}

X普通字符恰好n次

X{n,}

X普通字符至少n次

X{n,m}

X普通字符至少n次,但是不超过m次


 

例子:

         System.out.println("a".matches(".") ); //true

         System.out.println("a".matches("a") ); //true

         System.out.println("a".matches("a?"));

         System.out.println("aaa".matches("a*") );

         System.out.println("".matches("a+") );

         System.out.println("aaaaa".matches("a{5}") );

         System.out.println("aaaaaaaaa".matches("a{5,8}") );

         System.out.println("aaa".matches("a{5,}") );

         System.out.println("aaaaab".matches("a{5,}") );

(3)字符表示范围


[abc]

a、b 或 c(简单类)

[^abc]

任何字符,除了 a、b 或 c(否定)

[a-zA-Z]

a 到 z 或 A 到 Z,两头的字母包括在内(范围)

[a-d[m-p]]

a 到 d 或 m 到 p:[a-dm-p](并集)

[a-z&&[def]]

d、e 或 f(交集)

[a-z&&[^bc]]

a 到 z,除了 b 和 c:[ad-z](减去)

[a-z&&[^m-p]]

a 到 z,而非 m 到 p:[a-lq-z](减去)


 

例子:

         System.out.println("a".matches("[a]") );

         System.out.println("aa".matches("[a]+") );

         System.out.println("abc".matches("[abc]{3,}") );

         System.out.println("abc".matches("[abc]+") );

         System.out.println("dshfshfu1".matches("[^abc]+") );

         System.out.println("abcdsaA".matches("[a-z]{5,}") );

         System.out.println("abcdsaA12".matches("[a-zA-Z]{5,}") );

         System.out.println("abcdsaA12".matches("[a-zA-Z0-9]{5,}") );

         System.out.println( "abdxyz".matches("[a-c[x-z]]+"));

         System.out.println("bcbcbc".matches("[a-z&&[b-c]]{5,}"));

         System.out.println("tretrt".matches("[a-z&&[^b-c]]{5,}"));

3、正则表达式的应用

(1)匹配功能

需求:校验QQ号,要求:必须是5~15位数字,0不能开头。没有正则表达式之前:

public static void checkQQ(String qq) {
         int len = qq.length();
         if(len>=5&& len <=15) {
                   if(!qq.startsWith("0")){
                            try{
                                     longl = Long.parseLong(qq);
                                     System.out.println("qq:"+l);
                            }catch (NumberFormatException e) {
                                     System.out.println("出现非法字符");
                            }
                   } else {
                            System.out.println("不可以0开头");
                   }
         } else {
                   System.out.println("QQ号长度错误");
         }
}

 

有了正则表达式之后:

[1-9][0-9]{4,14}

[1-9]表示是第一位数字是会出现1-9范围之间的其中一个,下来的数字范围会出现在0-9之间,至少出现4次,最多出现14次。

 

public static void checkQQ2() {
         String qq ="12345";
         String reg ="[1-9][0-9]{4,14}";
matches(reg);
         System.out.println("b="+b);
}

 

需求:匹配是否为一个合法的手机号码。

public static void checkTel() {
         String tel ="25800001111";
         String reg ="1[35]\\d{9}";
         boolean b=tel.matches(reg);
         System.out.println(tel+":"+b);
}

手机号的匹配规则,这是是指13和15开头的号码段,手机号总共是11位:

         1[35]\\d{9}

第1位的1表示一定是以1开头,后面[35]表示3或5,\\d{9}中\c表示数字,这里是有9个数字。

(2)切割功能

根据空格对一段字符串进行切割。

public static void splitDemo() {
         String str ="aa.bb.cc";
         str = "-1     99   4    23";
split(" +");
         for(String s : arr) {
                   System.out.println(s);
         }
}

 

根据重叠词进行切割。

public static void splitDemo2() {
         String str ="sdqqfgkkkhjppppkl";
split("(.)\\1+");
         for(String s : arr) {
                   System.out.println(s);
         }
}

注意:为了提高规则复用,用()进行封装,每一个括号都有一个编号,从1开始,为了复用这个规则。可以通过编号来完成该规则的调用。需要对编号数字进行转义,\\1就代表获取1组规则。

(3)替换功能

把手机号替换成“*”号。

 

String str = "联系我:13567012119联系我:13567012119联系我:13567012119联系我:13567012119联系我:13567012119联系我:13567012119";

String reg= "1[34578]\\d{9}";

str = str.replaceAll(reg,"******");

System.out.println("替换后的帖子:"+ str);

输出结果:替换后的帖子:联系我:******联系我:******联系我:******联系我:******联系我:******联系我:******

(4)获取

获取需要使用到两个正则对象:正则对象Pattern和匹配器Matcher。用法:

Pattern p = Pattern.compile("a*b");

Matcher m = p.matcher("aaaaab");

boolean b = m.matches();

 

步骤:

(1)先将正则表达式编译成正则对象。使用的是Pattern类一个静态的方法。compile(regex);

(2)让正则对象和要操作的字符串相关联,通过matcher方法完成,并返回匹配器对象。

(3)通过匹配器对象的方法将正则模式作用到字符串上对字符串进行针对性的功能操作,即判断是否匹配

 

示例:请找出文本中的所有电话号码



 

/*
          * boolean b1 = matcher.find(); 
          * System.out.println(b1); 
          * System.out.println(matcher.group());
          * boolean b2 = matcher.find(); 
          * System.out.println(b2); 
          * System.out.println(matcher.group());
          */
         public voidfindNumber() {
                   Stringstring = "我的手机是18988888888,我曾用过18987654321,还用过18812345678";
                   String regex= "1[3578]\\d{9}";
                   Patternpattern = Pattern.compile(regex);
                   Matchermatcher = pattern.matcher(string);
                   while(matcher.find()) {
                            Stringgroup = matcher.group();
                            System.out.println(group);
                   }
         }

4、System

System用于获取系统的属性。它不能被实例化。


字段、方法声明

字段、方法作用

public final static InputStream in

标准输入流,键盘输入

public final static PrintStream out

打印输出流

public final static PrintStream err

错误输出流

public static void gc()

运行垃圾回收器

public static void exit(int status)

退出JVM,0为正常退出。

public static long currentTimeMillis()

1970.1.1到现在的毫秒数

public static native long nanoTime()

1970.1.1到现在的纳秒数

pubiic static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)

拷贝数组


 

(1)系统属性

//获取系统属性

Properties ps = System.getProperties();

System.out.println(ps);

//获取操作系统名称

String osName = System.getProperty("os.name");

System.out.println(osName);

(2)两个重要常量

System.in

标准输入(键盘)

Scanner scanner = new Scanner(System.in);

System.out

标准输出(屏幕)

System.out作为PrintStream打印流类的的对象实现标准输出,可以调用它的print、println或write方法来输出各种类型的数据。

print和println的参数完全一样,不同之处在于println输出后换行而print不换行。

write方法用来输出字节数组,在输出时不换行。

 

(3)自动装箱/拆箱

自动装箱是把一个基本数据类型直接赋给对应的包装类。

自动拆箱是把一个包装类对象直接赋给对应的基本数据类型。

A、典型应用

Java基本类型都有一个对应的包装类型,它们之间可以互相转换,不需要强制造型。例如:

Integer i = 1;       //自动装箱

int j = i;                        //自动拆箱

B、基本数据类型转换成字符串:

1、“+”

int i = 100;

String str = "" + 100;

 

2、toString

Integer.toString(34); //将34变成了”34”

C、字符串变基本数据类型

parseXXX(String s)方法是静态的,参数必须是数字的字符串格式

 

int parseInt = Integer.parseInt("123");

double parseInt2 = Double.parseDouble("3.14");

boolean b = Boolean.parseBoolean("true");

三、日期时间

1、基础

(1)时间的长整数表示

在Java中,使用long表示从1970-01-01 00:00:00:000开始到现在所经过的毫秒数。

例如:longcurrentTime = java.lang.System.currentTimeMillis();

(2)日期类

现在,Date中大部分方法已经过时了,推荐使用Calendar类。

 


java.util.Date

在Java程序中,通常使用它表示日期

java.sql.Date

在数据库操作中表示日期。JDBC不直接支持java.util.Date

Calendar(*)

日历类,封装了年月日时分秒和时区。

SimpleDateFormat

实现日期和字符串间的转换。


 

2、Date对象


方法声明

方法作用

public Date()

构造方法

public Date(long date)

传入参数为自 1970 年 1 月 1 日 00:00:00 GMT 以来的毫秒数。

public long getTime()

1970.1.1至今的毫秒数

public void setTime(long time)

设置毫秒数


 

请注意导包:java.util.Date

 

创建Date对象的最简单方式就是获得当前日期时间:

Date nowDate = new Date();

System.out.println(nowDate);

输出结果:Sun Apr08 22:27:50 CST 2018

 

获取1970.1.1至今的毫秒数

long time = nowDate.getTime();

System.out.println(time);

输出结果:1523198449467

3、SimpleDateFormat

DateFormat是日期/时间格式化子类的抽象类,它以与语言无关的方式格式化,并解析日期或时间。通常使用其子类SimpleDateFormat。

 


方法声明

方法作用

public SimpleDateFormat()

空参构造

public SimpleDateFormat(String pattern)

指定模式的构造方法。

在SimpleDateFormat的模式串中,注意各个字符的含义,以及字符的个数和大小写(请参见文档)

public final String format(Date date)

将日期转为字符串表示

public Date parse(String source)

将字符串表示转为日期


 

(1)日期的默认字符串格式

日期的默认字符串格式使用国际标准表示:

System.out.println("nowDate.toString(): " + nowDate);

输出结果:

Sun Apr 08 22:27:50 CST 2018

(2)定制日期输出格式

默认的日期字符串不符合国内的阅读习惯,可以使用SimpleDateFormat定制日期输出格式:

 

Date nowDate = new Date();

SimpleDateFormat simpleDateFormat = newSimpleDateFormat("yyyy年MM月dd日");

String formatDate =simpleDateFormat.format(nowDate);

System.out.println("格式化后的日期:"+ formatDate);

输出结果:格式化后的日期:2018年04月08日

 

其余类似格式请参见文档描述

(3)使用日期字符串创建日期对象

SimpleDateFormat simpleDateFormat = newSimpleDateFormat("yyyy-MM-dd HH:mm:ss");

String stringDate = "2018-04-0822:36:01";

Date date =simpleDateFormat.parse(stringDate);

//再转回去

String formatDate =simpleDateFormat.format(date);

System.out.println("格式化后的日期:"+ formatDate);

4、Calendar


方法声明

方法作用

static Calendar getInstance()

使用默认时区和语言环境获得一个日历

int get(int field)

返回给定日历字段的值

void add(int field,int amount)

根据日历的规则,为给定的日历字段添加或减去指定的时间量

void set(int field, int value)

设置"年/月/日/小时/分钟/秒/微秒"等值

void set(int year,int month,int date)

设置日历字段 YEAR、MONTH 和 DAY_OF_MONTH 的值


 

(1)创建日历对象

A、获得系统的日历

Calendar calendar = Calendar.getInstance();          // 单例模式

B、使用set方法设置

使用set(intfield, int value)实现。例如:

         Calendar calendar =Calendar.getInstance();

YEAR, 2013);                           //年

MONTH, 7);                            //月,从0开始,7表示8月

DAY_OF_MONTH, 2); //日

HOUR_OF_DAY, 17);   //24小时计时

MINUTE, 35);                         //分

SECOND, 44);                         //秒

 

使用set(intyear, int month, int day, int hour, int minute, int second)实现。例如:

Calendar calendar = Calendar.getInstance();

calendar.set(2013, 7, 2, 17, 35, 44)

C、Calendar和Date

1、根据Date对象创建Calendar

         Calendar calendar =Calendar.getInstance();

         calendar.setTime(newDate());

注意:Calendar没有构造函数接收Date对象,因此要先创建一个Calendar对象,然后使用setTime设置Date对象。

 

2、根据Calendar对象获取Date对象

         Calendar calendar =Calendar.getInstance();

         Date date =calendar.getTime();

(2)常用操作

A、获取年月日时分秒

// 获得当前时间

Calendar calendar = Calendar.getInstance();

 

// 获取年、月、日、时、分、秒

int year = calendar.get(Calendar.YEAR);                                      // 年。计数从1开始

int month = calendar.get(Calendar.MONTH) + 1;                      // 月。计数从0开始

int day = calendar.get(Calendar.DAY_OF_MONTH);                 // 日。计数从1开始

int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);      // 范围是1-7。星期天返回1,星期一返回2,... 星期六返回7

 

int hour = calendar.get(Calendar.HOUR_OF_DAY);                            // 时。[0, 24)

int minute = calendar.get(Calendar.MINUTE);                           // 分。[0, 60)

int second = calendar.get(Calendar.SECOND);                           // 秒。[0, 60)

B、增减时间

使用add()方法,可以对日期各项进行增减。值为正数是增,值为负数是减。

 

例子:

         Calendar calendar =Calendar.getInstance();

         calendar.add(Calendar.HOUR_OF_DAY,3);                     //3小时以后

         calendar.add(Calendar.MINUTE,15);                     //15 分钟以后

         calendar.add(Calendar.MINUTE,-30);                       // 30分钟前

C、比较时间

使用compareTo比较时间。

 

例子:

         Calendar calendar =Calendar.getInstance();

         Calendar calendarNew =Calendar.getInstance();

        

         calendarNew.add(Calendar.HOUR,-5);         //设定为5小时以前,后者大;显示-1

         System.out.println("时间比较:" +calendarNew.compareTo(calendar));

        

         calendarNew.add(Calendar.HOUR,+7);          // 设定7小时以后,前者大;显示 1

         System.out.println("时间比较:" +calendarNew.compareTo(calendar));

D、计算时间差

可用Calendar.getTimeInMillis() 取得两个时间的微秒级的时间差,再加以换算即可。

 

比如获得相差天数,代码如下:

// 得微秒级时间差

long val = calendarEnd.getTimeInMillis() -calendarBegin.getTimeInMillis();

// 换算后得到天数

long day = val / (1000 * 60 * 60 * 24);

七、枚举

一些方法在运行时,它需要的数据不是任意的,必须在一定范围之内,在Java1.5之后可以使用枚举类型解决。例如:交通灯(红、黄、绿),性别(男、女),星期(星期一、二、三…..),分数等级(A、B、C、D、E)。

1、简单枚举类型

JDK 1.5新增的 enum 关键字用于定义一个枚举类型,使用见名思义的“名字”来替代常量定义,提供了更好的可读性。

(1)每个枚举常量默认都使用整数值表示

例如:

         enum Season {

                   SPRING,SUMMER, AUTUMN, WINTER;

         }

 

在Java内部,为每个枚举值都默认指定一个整数值,从0开始,依次加1。测试如下:

public static void main(String[] args) {

         System.out.println(Season.SPRING);

         System.out.println(Season.SUMMER);

         System.out.println(Season.AUTUMN);

         System.out.println(Season.WINTER);

}

(2)枚举可以使用==直接比较。

例如:

         System.out.println(Season.SPRING== Season.SUMMER);              // false

(3)枚举类型可用于switch语句

JDK1.5中扩展了switch语句的要求,除了可以接收整数类型外,还可以接收枚举类型。

 

public static void main(String[] args) {

         Season s =Season.SUMMER;

         switch(s) {

                   case SPRING:

                            System.out.println("春天");

                            break;

                   case SUMMER:

                            System.out.println("夏天");

                            break;

                   case AUTUMN:

                            System.out.println("秋天");

                            break;

                   case WINTER:

                            System.out.println("冬天");

                            break;

         }

}

2、枚举类

Java中声明的枚举类,都是java.lang.Enum的子类,它继承了Enum类的所有方法。

(1)Enum方法


name()

返回当前对象的名称

ordinal()

返回当前对象的索引

values()

返回所有对象

valueOf()

把其它类型数据转换为枚举类型


 

(2)实现细节

1、枚举也是一个类。

2、枚举值默认的修饰符是public static final。

3、枚举值的类型就是枚举类,枚举值是指向本类的对象引用。

4、枚举类中构造方法的默认修饰符是private的。

5、枚举类可以定义自己的成员变量与成员函数。

6、枚举类可以自定义构造函数,但是构造函数的修饰符必须是private。

7、枚举类可以有抽象方法,但是枚举值必须要实现抽象方法。

8、枚举值必须要位置枚举类的第一个语句。

(3)实例

enum Gender {
         MALE("男"),FEMALE("女");             // 每个枚举值是一个Gender的静态实例
 
         // 成员变量
         private String info;
 
         // 私有构造函数
         private Gender() {
         }
         private Gender(Stringinfo) {
                   this.info =info;
         }
 
         // 成员方法
         public StringgetInfo() {
                   return info;
         }
}

 

编译后生成的代码如下,帮助理解枚举类的实现细节:

final class Gender extends java.lang.Enum {
MALE = new Gender("男");
FEMALE = new Gender("女");
         
         private String info;
         private Gender() {
         }
         private Gender(Stringinfo) {
                   this.info =info;
         }
         public StringgetInfo() {
                   return info;
         }
}

其中每一个枚举值都是枚举类的实例对象,只不过是静态常量。

(4)应用枚举类

public class EnumClassDemo {
         public static voidmain(String[] args) {
                   Gender male= Gender.MALE;
                   System.out.println(male.getInfo());
         }
}