开发心得:看着正确数据,从左到右书写正则表达式
在Java中,我们经常需要验证一些字符串,例如:年龄必须是2位的数字、用户名必须是8位长度而且只能包含大小写字母、数字等。正则表达式就是用来验证各种字符串的规则。它内部描述了一些规则,我们可以验证用户输入的字符串是否匹配这个规则。
正则表达式在开发中极为重要:我们对账号的输入和对密码的处理就用到了正则表达式。
先看一个不使用正则表达式验证的例子:下面的程序让用户输入一个QQ号码,我们要验证:
QQ号码必须是6--20位长度
而且必须全部是数字
而且首位不能为0
package com.itheima.a05regex; public class Test1 { public static void main(String[] args) { // 假如现在要求校验一个qq号码是否正确,6位及20位之内,0不能在开头,必须全部是数字 。 System.out.println(checkQQ("23658977452")); System.out.println(checkQQ("236589775223589775223589775223589775223658977452")); } public static boolean checkQQ(String qq){ //1.校验长度 if(qq.length() < 6 || qq.length() > 20){ return false; } //2.校验开头 char c = qq.charAt(0); if(c == '0'){ return false; } //3.校验内容 for (int i = 0; i < qq.length(); i++) { //i索引 charAt(i)字符 char at = qq.charAt(i); if(at < '0' || at > '9'){ return false; } } //4.当循环结束之后,还没有发现不是数字的 return true; } }
不用正则表达式手写方法来判定这种规则,比较麻烦,这个规则比较简单,如果遇到更复杂的规则就给手写的话就更麻烦了。
使用正则表达式验证:
public class Demo { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("请输入你的QQ号码:"); String qq = sc.next(); System.out.println(checkQQ2(qq)); } //使用正则表达式验证 private static boolean checkQQ2(String qq){ String regex = "[1-9]\\d{5,19}";//正则表达式 return qq.matches(regex); } }
上面程序checkQQ2()方法中String类型的变量regex就存储了一个"正则表达式 ",而这个正则表达式就描述了我们需要的三个规则。matches()方法是String类的一个方法,用于接收一个正则表达式,并将"本对象"与参数"正则表达式"进行匹配,如果本对象符合正则表达式的规则,则返回true,否则返回false。
我们接下来就重点学习怎样写正则表达式
语法示例:
[abc]:代表a或者b,或者c字符中的一个。
[^abc]:代表除a,b,c以外的任何字符。
[a-z]:代表a-z的所有小写字符中的一个。
[A-Z]:代表A-Z的所有大写字符中的一个。
[0-9]:代表0-9之间的某一个数字字符。
[a-zA-Z0-9]:代表a-z或者A-Z或者0-9之间的任意一个字符。
[a-dm-p]:a 到 d 或 m 到 p之间的任意一个字符。
代码示例:
public class Demo { public static void main(String[] args) { String str = "ead"; //1.验证str是否以h开头,以d结尾,中间是a,e,i,o,u中某个字符 String regex = "h[aeiou]d"; System.out.println("1." + str.matches(regex));//false //2.验证str是否以h开头,以d结尾,中间不是a,e,i,o,u中的某个字符 regex = "h[^aeiou]d"; System.out.println("2." + str.matches(regex));//false //3.验证str是否a-z的任何一个小写字符开头,后跟ad regex = "[a-z]ad"; System.out.println("3." + str.matches(regex));//true //4.验证str是否以a-d或者m-p之间某个字符开头,后跟ad regex = "[[a-d][m-p]]ad"; System.out.println("4." + str.matches(regex));//false regex = "[\\W]ad"; System.out.println("5." + str.matches(regex));//false } }
语法示例:
&&:并且
| :或者
代码示例:
public class Demo { public static void main(String[] args) { String str = "had"; //1.要求字符串是小写辅音字符开头,后跟ad String regex = "[a-z&&[^aeiou]]ad"; System.out.println("1." + str.matches(regex));//true //2.要求字符串是aeiou中的某个字符开头,后跟ad regex = "[aoeiu]ad";//这种写法相当于:regex = "[aeiou]ad"; System.out.println("2." + str.matches(regex));//false regex = "[a|o|e|i|u]ad";//这种写法相当于:regex = "[aeiou]ad"; System.out.println("3." + str.matches(regex));//false } }
语法示例:
"." : 匹配任何字符。(记住)
"\d":任何数字[0-9]的简写;(记住)
"\D":任何非数字[^0-9]的简写;
"\s": 空白字符:[ \t\n\x0B\f\r] 的简写
"\S": 非空白字符:[^\s] 的简写
"\w":单词字符:[a-zA-Z_0-9]的简写
"\W":非单词字符:[^\w](除了英文字母、数字和下划线)
代码示例:
public class Demo { public static void main(String[] args) { String str = "258"; //1.验证str是否3位数字 String regex = "\\d\\d\\d"; System.out.println("1." + str.matches(regex));//true //2.验证手机号:1开头,第二位:3/5/8,剩下9位都是0-9的数字 str = "13513153355";//要验证的字符串 regex = "1[358]\\d\\d\\d\\d\\d\\d\\d\\d\\d";//正则表达式 System.out.println("2." + str.matches(regex));//true //3.验证字符串是否以h开头,以d结尾,中间是任何字符 str = "had";//要验证的字符串 regex = "h.d";//正则表达式 System.out.println("3." + str.matches(regex));//true //4.验证str是否是:had. str = "had.";//要验证的字符串 regex = "had\\.";//\\.代表'.'符号,因为.在正则中被预定义为"任意字符",不能直接使用 System.out.println("4." + str.matches(regex));//true } }
语法示例:
X? : 0次或1次
X* : 0次到多次(*的意思是可以为任意次)
X+ : 1次或多次
X{n} : 恰好n次
X{n,} : 至少n次
X{n,m}: n到m次(n和m都是包含的)
代码示例:
public class Demo { public static void main(String[] args) { String str = ""; //1.验证str是否是三位数字 str = "012"; String regex = "\\d{3}"; System.out.println("1." + str.matches(regex)); //2.验证str是否是多位数字 str = "88932054782342"; regex = "\\d+"; System.out.println("2." + str.matches(regex)); //3.验证str是否是手机号: str = "13813183388"; regex = "1[358]\\d{9}"; System.out.println("3." + str.matches(regex)); //4.验证小数:必须出现小数点,但是只能出现1次 String s2 = "3.1"; regex = "\\d*\\.{1}\\d+"; System.out.println("4." + s2.matches(regex)); //5.验证小数:小数点可以不出现,也可以出现1次 regex = "\\d+\\.?\\d+"; System.out.println("5." + s2.matches(regex)); //6.验证小数:要求匹配:3、3.、3.14、+3.14、-3. s2 = "-3."; regex = "[+-]\\d+\\.?\\d*"; System.out.println("6." + s2.matches(regex)); //7.验证qq号码:1).5--15位;2).全部是数字;3).第一位不是0 s2 = "1695827736"; regex = "[1-9]\\d{4,14}"; System.out.println("7." + s2.matches(regex)); } }
至于运行结果大家可复制到idea中去看看。
String某些方法是不能识别正则表达式的。怎么区别哪些方法能否接受正则表达式呢?
打开我们的JDK文档,找到matches方法:
发现形参的名字是regex,那么只要String类中,形参是以regex命名的,都表示可以接受正则表达式。如下
它们都能接受正则表达式。
String类的split()方法原型:
public String[] split(String regex)//参数regex就是一个正则表达式。可以将当前字符串中匹配regex正则表达式的符号作为"分隔符"来切割字符串。
split()函数之前以为是简单分割字符串的,但是它的真正用处是结合正则表达式分割字符串。
代码示例:
String names = "小路dqwefqwfqwfwq12312蓉儿dqwefqwfqwfwq12312小何"; //要求1:把字符串中的三个姓名切割出来 String[] arr = names.split("\\w+"); //String[] arr = names.split("\\."); for (int i = 0; i < arr.length; i++) { System.out.print(arr[i] + " "); } System.out.println();
String类的replaceAll()方法原型:
public String replaceAll(String regex,String newStr) //参数regex就是一个正则表达式。可以将当前字符串中匹配regex正则表达式的字符串替换为newStr。
代码示例:
//要求2:把字符串中三个姓名之间的字母替换为vs String names = "小路dqwefqwfqwfwq12312蓉儿dqwefqwfqwfwq12312小何"; //切记:字符串本身是不可变的,不管是截取,还是替换还是其他操作,不能改变字符串本身 //只有返回值才是操作之后的结果 String result = names.replaceAll("\\w+", "vs"); System.out.println(result);
运行结果:
代码示例:
//验证手机号码 13112345678 13712345667 13945679027 String regex1 = "[1-9][3-9]\\d{9}"; System.out.println("13112345678".matches(regex1)); System.out.println("13712345667".matches(regex1)); System.out.println("13945679027".matches(regex1)); System.out.println("139456790271".matches(regex1));
代码示例:
//验证座机电话号码 020-2324242 02122442 027-42424 0712-3242434 String regex2 = "0\\d{2,3}-?[1-9]\\d{4,9}";//要么2位要么3位的写法是{2,3},这个点要掌握 System.out.println("020-2324242".matches(regex2)); System.out.println("02122442".matches(regex2)); System.out.println("027-42424".matches(regex2)); System.out.println("0712-3242434".matches(regex2));
代码示例:
//验证邮箱[email protected] [email protected] [email protected] [email protected] //把邮箱分为三段来写: //第一段:@的左半部分,任意的字母数字下划线,至少出现一次 \\w+ //第二段:@只能出现一次 @ //第三段:比较难,我们可以把第三段继续分为三段 //3-1:点的左半部分:字母和数字可以出现2~8次。 [\w^_]{2,8} //3-2:点 \\. //3-3:点的右半部分:大写字母和小写字母只能出现2~3次。 [a-zA-Z]{2,3} //又因为,有的邮箱,还有可能会有点,所以把3-2和3-3看成一个整体,这个整体可以出现1~2次。 String regex3 = "\\w+@[\\w^_]{2,8}(\\.[a-zA-Z]{2,3}){1,2}";//()可以对某一部分整体进行操作,{}是对位数进行限定,[]是对某一位进行限定三种括号用法各不相同!!一定要注意区别。 System.out.println("[email protected]".matches(regex3)); System.out.println("[email protected]".matches(regex3)); System.out.println("[email protected]".matches(regex3)); System.out.println("[email protected]".matches(regex3));
正则表达式的核心:
1、掌握基本规则
2、掌握三种括号的用法
3、正则表达式的应用场景:一个系统在用户注册账户的时候对数据进行校验
方法名 | 说明 |
---|---|
public static String toString(类型[] a) | 把数组变成字符串返回 |
public static void sort(类型[] a) | 对数组进行默认升序排序 |
public static int binarySearch(int[] a, int key) | 二分搜索数组中的数据,存在返回索引,不存在返回负插入点-1 |
代码示例:
public class Demo1 { public static void main(String[] args) { //1.定义数组 //int[] arr = {4,1,3,2,5}; //对数组中的数据进行排序 //Arrays.sort(arr); //把数组里面所有的数据,拼接在一起,变成一个字符串给你返回 //String result = Arrays.toString(arr); //System.out.println(result); //System.out.println(Arrays.toString(arr)); //binarySearch作用:查找某一个数据在数组中出现的索引 //前提:数组必须是从小到大,有序的 //如果要查询的数据不存在,那么返回负数 //了解:-插入点-1 int[] arr = {1,2,3,4,5,7,9,10,20,30}; int index = Arrays.binarySearch(arr, 0); System.out.println(index); } }
运行结果:
Lambda省去面向对象的条条框框,格式由3个部分组成:
一些参数
一个箭头
一段代码
Lambda表达式的标准格式为:
(参数类型 参数名称) -> { 代码语句 }
格式说明:
小括号内的语法与传统方法参数列表一致:无参数则留空;多个参数则用逗号分隔。
->
是新引入的语法格式,代表指向动作。
大括号内的语法与传统方法体要求基本一致。
匿名内部类与lambda对比:
new Thread(new Runnable() { @Override public void run() { System.out.println("多线程任务执行!"); } }).start();
仔细分析该代码中,Runnable
接口只有一个run
方法的定义:
public abstract void run();
即制定了一种做事情的方案(其实就是一个方法):
无参数:不需要任何条件即可执行该方案。
无返回值:该方案不产生任何结果。
代码块(方法体):该方案的具体执行步骤。
同样的语义体现在Lambda
语法中,要更加简单:
() -> System.out.println("多线程任务执行!")
前面的一对小括号即run
方法的参数(无),代表不需要任何条件;
中间的一个箭头代表将前面的参数传递给后面的代码;
后面的输出语句即业务逻辑代码。
看一个案例:
省略规则
在Lambda标准格式的基础上,使用省略写法的规则为:
小括号内参数的类型可以省略;
如果小括号内有且仅有一个参,则小括号可以省略;
如果大括号内有且仅有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号。
备注:掌握这些省略规则后,请对应地回顾本章开头的多线程案例。
可推导即可省略
Lambda强调的是“做什么”而不是“怎么做”,所以凡是可以根据上下文推导得知的信息,都可以省略。例如上例还可以使用Lambda的省略写法:
Runnable接口简化: 1. () -> System.out.println("多线程任务执行!") Comparator接口简化: 2. Arrays.sort(array, (a, b) -> a.getAge() - b.getAge());
案例:
未简化前:
简化后:
注意省略方法体末尾那个分号。
Lambda的语法非常简洁,完全没有面向对象复杂的束缚。但是使用时有几个问题需要特别注意:
使用Lambda必须具有接口,且要求接口中有且仅有一个抽象方法。(函数式接口) 无论是JDK内置的Runnable
、Comparator
接口还是自定义的接口,只有当接口中的抽象方法存在且唯一时,才可以使用Lambda。
使用Lambda必须具有上下文推断。 也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。
备注:有且仅有一个抽象方法的接口,称为“函数式接口”。