1.1 正则表达式
1.1.1好处
- 一个正则表达式就是一个描述规则的字符串
- 只需要编写正确的规则,就可以让正则表达式引擎去判断目标字符串是否符合规则
- 正则表达式是一套标准,可以用于任何语言
- JDK 内置正则表达式引擎: java.util.regex
示例:判断用户输入的年份是否是19xx年:
java
public class TestRegex {
// \\为转义字符,d 代表0-9的数字
public static boolean is19xx(String s) {
if(s == null) {
return false;
}
return s.matches("19\\d\\d");
}
public static void main(String[] args) {
System.out.println(is19xx("1991")); // true
System.out.println(is19xx("1900")); // true
System.out.println(is19xx("1911")); // true
System.out.println(is19xx("1934")); // true
System.out.println(is19xx(" ")); // false
System.out.println(is19xx(null)); // false
System.out.println(is19xx("19910")); // false
System.out.println(is19xx("A90")); // false
System.out.println(is19xx("2022")); // false
}
}
1.1.2 匹配规则
- 从左到右按规则匹配
1.1.3 如何编写正则表达式:
-
精确匹配"abc"
-
-
精确匹配: "a
\&
c",特殊字符需要转义:
-
精确匹配: "a
\548c
c",非ascII 字符 用\u#### 表示
-
特殊字符
.
可以匹配一个任意字符: "a.
c"
-
符号
\d
可以匹配一个数字: "00/d
"
-
符号
\w
可以匹配一个字母,数字或者下划线: "java\w
"
-
符号
\s
可以匹配一个空白字符 "A\s
B"
-
符号
\D
可以匹配一个非数字 : "00\D":
-
符号
\W
可以匹配一个非字母,数字或下划线: "java\W
"
-
符号
\S
可以匹配一个非空白字符:"A\S
B"
-
修饰符
*
可以匹配任意个字符:"A\d*
" -
修饰符
+
可以匹配至少一个字符: "A\d+
"
-
修饰符
?
可以匹配零个或1个字符:"A\d?
"
-
修饰符
{n}
可以匹配n个字符:"\d{6}"
-
修饰符
{n,m}
可以匹配n-m个字符:"\d{3,5q}"
-
修饰符
{n,}
可以匹配至少n个字符: "\d{3,}
"
bash
/**
* 匹配电话号码 区号-电话
* @param s
* @return
*/
public static boolean isValidTel(String s) {
// return s.matches("\\d{3,4}\\-\\d{6,8}");
return s.matches("0\\d{2,3}\\-\\d{6,8}"); // 严谨一些, 我们想让区号以0开头,
}
public static void main(String[] args) {
System.out.println(isValidTel("010-123456")); // true
System.out.println(isValidTel("010-12345678")); // true
System.out.println(isValidTel("0123-123456")); // true
System.out.println(isValidTel("0123-12345678")); // true
System.out.println(isValidTel("123-12345678")); // false
System.out.println(isValidTel("123-0123456")); // false
System.out.println(isValidTel("010#012345678")); // false
System.out.println(isValidTel("010X012345678")); // false
System.out.println(isValidTel("01-012345678")); // false
System.out.println(isValidTel("01234-12345678")); // false
System.out.println(isValidTel("01A-12345678")); // false
System.out.println(isValidTel("0123-12345")); // false
System.out.println(isValidTel("0123-12345X")); // false
System.out.println(isValidTel("0123-123456789")); // false
System.out.println(isValidTel("0123-12345678X")); // false
}
正则表达式匹配规则总结:
2.1 复杂正则表达式
-
^
和$
匹配开头和结尾: "^A\d{3}$
"
-
[...]
可以匹配范围内的字符: "[abc]
1"
-
[...]
可以匹配范围内的字符: "[a-f]
1"
-
[...]
可以匹配范围内的字符: "[a-f0-9]
{6}"
-
[...]
可以匹配范围内的字符: "[a-f0-9_]
{6}"
-
[^...]
可以匹配非范围内的字符: "[^0-9_]
{6}"
-
AB|CD 可以匹配AB或CD:"
java|pnp
"
-
AB|CD 可以匹配AB或CD:"
learn\s(java|php)
"
-
AB|CD 可以匹配AB或CD:"
learn\sjava|php
"
bash
/**
* 匹配5-10位qq号码
* @param s
* @return
*/
public static boolean isValidQQ(String s){
return s.matches("^[1-9]\\d{4,9}$");
}
/**
* 匹配电话号码 区号-电话
* @param s
* @return
*/
public static boolean isValidTel(String s) {
// return s.matches("\\d{3,4}\\-\\d{6,8}");
// return s.matches("0\\d{2,3}\\-\\d{6,8}"); // 严谨一些, 我们想让区号以0开头,
return s.matches("0\\d{2,3}\\-[1-9]\\d{5,7}"); // 区号以0开头,并且电话号码1-9 数字开头
}
正则表达式匹配规则:
3.1 分组匹配规则
-
(... ) 可以分组: "
(\d{4})\-(\d{1,2})\-(\d{1,2})
"
正则表达式分组举例
-
提取电话号码 ###-########
不加小括号的作用是匹配, 加上小括号后,匹配完成后提取
-
提取24小时时间 ##:##
String.matches vs Pattern.matcher:
反复使用一个正则表达式字符串进行快速匹配效率较低:
- 可以把正则表达式字符串编译为Pattern对象
使用Matcher.group(n) 可以快速提取子串:
java
static Pattern p = Pattern.compile("^(0\\d{2,3})\\-([1-9]\\d{5,7})$");
public static void parse(String s) {
Matcher matcher = p.matcher(s);
if (matcher.matches()) {
System.out.println(matcher.group(0)); // 010-123456
System.out.println(matcher.group(1)); // 010
System.out.println(matcher.group(2)); // 123456
}
}
public static void main(String[] args) {
parse("010-123456");
}
总结
正则表达式分组可以通过Matcher对象快速提取子串
- group(0) 表示匹配的整个字符串
- group(1) 表示第1子串
- group(2) 表示第2个子串
- ...
4. 非贪婪匹配
给定一个字符串表示的数字
-
判断该数字末尾0的个数 ``
正则表达式默认使用贪婪匹配:
-
尽可能多地向后匹配
-
使用? 实现非贪婪匹配
java
/**
* 非贪婪匹配
*/
public static void zeros(String s) throws IllegalAccessException {
// Pattern p = Pattern.compile("^\\d+(0*)$"); //\d+ 默认贪婪匹配,尽可能的向后匹配,,所以后面0* 匹配的是空
Pattern p = Pattern.compile("^\\d+?(0*)$"); //\d+? 开启贪婪匹配
Matcher m = p.matcher(s);
if (m.matches()) {
String zeroStr = m.group(1);
System.out.println(zeroStr.length());
} else {
System.out.println("not a number");
}
}
public static void main(String[] args) throws IllegalAccessException {
zeros("1231"); // 0
zeros("12310"); // 1
zeros("123100"); //2
zeros("1231000");//3
}
总结:
- 正则表达式匹配默认使用贪婪匹配
- 使用
?
表示对某一规则进行非贪婪匹配 - 注意区分
?
号的含义\d??
5. 搜索和替换
使用正则表达式分割字符串
- String[] String.split(String regex)
使用正则表达式搜索字符串
- Matcher.find()
匹配指定单词匹配所有单词 匹配单词中所有带o的单词
使用正则表达式替换字符串
- String.replaceAll()
将多个空格替换为1个空格
对每个单词前后都加上<b>标签
总结
使用正则表达式可以:
- 分割字符串 String.split()
- 搜索字符串 Matcher.find()
- 替换字符串 String.replaceAll()