文章目录
文章目录
一、了解正则表达式
1.1 什么是正则表达式?
正则表达式,又称规则表达式。正则表达式是对字符 串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。通常被用来检索、替换那些符合某个模式(规则)的文本。在Java Web中用于前端校验的字符串限制。
1.2 正则表达式的特点
- 灵活性、逻辑性和功能性非常强
- 可以迅速地用极简单的方式达到字符串的复杂控制
- 对于刚接触的人来说,比较晦涩难懂
1.3 正则表达式的语法
1.3.1 简单的语法使用
复杂版:var patt=new RegExp(pattern,modifiers);
简单版:var patt=/pattern/modifiers;
1.3.2 语法规范
正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。
普通字符
普通字符包括没有显式指定为元字符的所有可打印和不可打印字符。这包括所有大写和小写字母、所有数字、所有标点符号和一些其他符号。
非打印字符
非打印字符也可以是正则表达式的组成部分。下表列出了表示非打印字符的转义序列
非打印字符 | 描述 |
---|---|
\cx | 匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 ‘c’ 字符。 |
\f | 匹配一个换页符。等价于 \x0c 和 \cL。 |
\n | 匹配一个换行符。等价于 \x0a 和 \cJ。 |
\r | 匹配一个回车符。等价于 \x0d 和 \cM。 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意 Unicode 正则表达式会匹配全角空格符。 |
\S | 匹配任何非空白字符。等价于[^ \f\n\r\t\v] |
\t | 匹配一个制表符。等价于 \x09 和 \cI。 |
\v | 匹配一个垂直制表符。等价于 \x0b 和 \cK。 |
特殊字符
所谓特殊字符,就是一些有特殊含义的字符,如上面说的 runoo*b 中的 *****,简单的说就是表示任何字符串的意思。如果要查找字符串中的 ***** 符号,则需要对 ***** 进行转义,即在其前加一个 \: runo*ob 匹配 runo*ob。
许多元字符要求在试图匹配它们时特别对待。若要匹配这些特殊字符,必须首先使字符"转义",即,将反斜杠字符 \ 放在它们前面。下表列出了正则表达式中的特殊字符
特别字符 | 描述 |
---|---|
$ | 匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 ‘\n’ 或 ‘\r’。要匹配 $ 字符本身,请使用 $。 |
( ) | 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 ( 和 )。 |
* | 匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 *。 |
+ | 匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 +。 |
. | 匹配除换行符 \n 之外的任何单字符。要匹配 . ,请使用 . 。 |
[ | 标记一个中括号表达式的开始。要匹配 [,请使用 [。 |
? | 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 ?。 |
\ | 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, ‘n’ 匹配字符 ‘n’。’\n’ 匹配换行符。序列 ‘\’ 匹配 “”,而 ‘(’ 则匹配 “(”。 |
^ | 匹配输入字符串的开始位置,除非在方括号表达式中使用,当该符号在方括号表达式中使用时,表示不接受该方括号表达式中的字符集合。要匹配 ^ 字符本身,请使用 ^。 |
{ | 标记限定符表达式的开始。要匹配 {,请使用 {。 |
| | 指明两项之间的一个选择。要匹配 | ,请使用 \ |
限定符
限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。有 ***** 或 + 或 ? 或 {n} 或 {n,} 或 {n,m} 共6种。正则表达式的限定符有:
字符 | 描述 |
---|---|
* | 匹配前面的子表达式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”。* 等价于{0,}。 |
+ | 匹配前面的子表达式一次或多次。例如,‘zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,}。 |
? | 匹配前面的子表达式零次或一次。例如,“do(es)?” 可以匹配 “do” 、 “does” 中的 “does” 、 “doxy” 中的 “do” 。? 等价于 {0,1}。 |
{n} | n 是一个非负整数。匹配确定的 n 次。例如,‘o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的两个 o。 |
{n,} | n 是一个非负整数。至少匹配n 次。例如,‘o{2,}’ 不能匹配 “Bob” 中的 ‘o’,但能匹配 “foooood” 中的所有 o。‘o{1,}’ 等价于 ‘o+’。‘o{0,}’ 则等价于 ‘o*’。 |
{n,m} | m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,“o{1,3}” 将匹配 “fooooood” 中的前三个 o。‘o{0,1}’ 等价于 ‘o?’。请注意在逗号和两个数之间不能有空格。 |
二、正则表达式的修饰符
修饰符用于执行区分大小写和全局匹配
修饰符 | 描述 |
---|---|
i | 执行对大小写不敏感的匹配。 |
g | 执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。 |
m | 执行多行匹配。 |
// 默认会区分大小写
var reg = /hello/
var flag = reg.test("Hello World")
console.log(flag) // false
// 添加i修饰符 不区分大小写
var reg2 = /hello/i
var flag2 = reg2.test("Hello World")
console.log(flag2) // true
var str = "I'm in a bad mood,really bad"
// 默认非全局匹配
var reg3 = /bad/
var newStr = str.replace(reg3,"good")
// 只替换了一个bad
console.log(newStr) // I'm in a good mood,really bad
// 全局匹配
var reg4 = /bad/g
var newStr2 = str.replace(reg4,"good")
// 替换了全局的bad为good
console.log(newStr2) // I'm in a good mood,really good
// 同时使用
var reg5 = /bad/gi
var newStr3 = reg5.test("i am a BaD");
console.log(newStr3);
三、正则表达式的多种修饰类
以下带有[]{}的都是正则表达式,[]内代表是对字符串的限制,而{}是代表长度。如果没有书写{}则默认长度为1
matches方法为正则表达式匹配方法,判断字符串是否满足正则表达式的校验(后面也会讲到)
3.1 字符类
字符类用于查找某个范围内的字符
表达式 | 描述 |
---|---|
[abc] | 查找方括号之间的任何字符。 |
[^abc] | 查找任何不在方括号之间的字符。 |
[0-9] | 查找任何从 0 至 9 的数字。 |
[a-z] | 查找任何从小写 a 到小写 z 的字符。 |
[A-Z] | 查找任何从大写 A 到大写 Z 的字符。 |
[A-z] | 查找任何从大写 A 到小写 z 的字符。 |
[abcd] | 查找给定集合内的任何字符。 |
[^abcd] | 查找给定集合外的任何字符。 |
(red|blue|green) | 查找任何指定的选项。 |
// [abc] a、b 或 c(简单类)
String reg1 = "[abc]";
System.out.println("a".matches(reg1)); // true
// [^abc] 任何字符,除了 a、b 或 c(否定)
String reg2 = "[^abc]";
System.out.println("d".matches(reg2)); // true
// [a-zA-Z] a 到 z 或 A 到 Z,两头的字母包括在内(范围)
String reg3 = "[a-zA-Z]";
System.out.println("ab".matches(reg3)); // false
// [0-9] 0到9的字符都包括
String reg4 = "[0-9]";
System.out.println("0".matches(reg4)); // true
// 需求:有一个字符,可以是a-z,也可以是A-Z,也可以是0-9,也可以是?
String reg5 = "[a-zA-Z0-9?]";
System.out.println("!".matches(reg5)); // false
3.2 元字符
元字符(Metacharacter)是拥有特殊含义的字符(注意:在使用的时候需要\\W,因为一个\默认为转义字符)
元字符 | 描述 |
---|---|
. | 查找单个字符,除了换行和行结束符。 |
\w | 查找单词字符。 |
\W | 查找非单词字符。 |
\d | 查找数字。 |
\D | 查找非数字字符。 |
\s | 查找空白字符。 |
\S | 查找非空白字符。 |
// . 任何字符。
String reg1 = ".";
System.out.println(">".matches(reg1)); // true
System.out.println(">a".matches(reg1)); // false
// \d 数字:[0-9]
String reg2 = "\\d";
System.out.println("11".matches(reg2)); // false
// \D 非数字:[^0-9]
String reg3 = "[^0-9]";
System.out.println("a".matches(reg3)); // true
System.out.println("11".matches(reg3)); // false
String reg4 = "\\D";
System.out.println("1".matches(reg4)); // false
// \w 单词字符:[a-zA-Z_0-9]
String reg5 = "\\w";
System.out.println("_".matches(reg5)); // true
String reg6 = "[a-zA-Z0-9_]";
System.out.println("_".matches(reg6)); // true
// \W 非单词字符:[^\w]
String reg7 = "[^a-zA-Z0-9_]";
System.out.println("a".matches(reg7)); // false
String reg8 = "[^\\w]";
System.out.println("!".matches(reg8)); // true
String reg9 = "[\\W]";
System.out.println("!".matches(reg9)); // true
// \s 空白字符:[ \t\n\x0B\f\r]
String reg10 = "\\s";
System.out.println(" ".matches(reg10)); // true
// \S 非空白字符:[^\s]
String reg11 = "\\S";
System.out.println("!".matches(reg11)); // true
3.3 匹配正则后的默认字符串
在使用以下四种正则表达式matches方法匹配字符串时,以下四种正则表达式表示的意义均是相同的!
- String reg1 = “abc”;
- 当reg1在使用matches进行对字符串的正则校验时,它已经不是一个普通的字符串了,"abc"隐式的存在[]和{},也就是等价于我们的第三种,为每一个字符添加了一个[]和{}
- String reg2 = [a][b][c];
- reg2正则表达式隐式存在{1}的长度,所以也是等于于我们的第三种
- String reg3 = [a]{1}[b]{1}[c]{1};
- reg3正则表达式是没有省略任何内容的正则表达式
- String reg4 = [abc]{3}
- reg4正则表达式可以解释为:在abc三个字符中,必须满足它的3个长度,也就是正则校验时规定字符串必须是abc
注意: 第一种看起来是一个字符串,当调用了matches方法进行字符串的正则校验时,该字符串摇身一变就成为了一个特殊的正则表达式!
3.4 数量词
量词 | 描述 |
---|---|
n+ | 匹配任何包含至少一个 n 的字符串。例如,/a+/ 匹配 “candy” 中的 “a”,“caaaaaaandy” 中所有的 “a”。 |
n* | 匹配任何包含零个或多个 n 的字符串。例如,/bo*/ 匹配 “A ghost booooed” 中的 “boooo”,“A bird warbled” 中的 “b”,但是不匹配 “A goat grunted”。 |
n? | 匹配任何包含零个或一个 n 的字符串。例如,/e?le?/ 匹配 “angel” 中的 “el”,“angle” 中的 “le”。 |
n{X} | 匹配包含 X 个 n 的序列的字符串。例如,/a{2}/ 不匹配 “candy,” 中的 “a”,但是匹配 “caandy,” 中的两个 “a”,且匹配 “caaandy.” 中的前两个 “a”。 |
n{X,} | X 是一个正整数。前面的模式 n 连续出现至少 X 次时匹配。例如,/a{2,}/ 不匹配 “candy” 中的 “a”,但是匹配 “caandy” 和 “caaaaaaandy.” 中所有的 “a”。 |
n{X,Y} | X 和 Y 为正整数。前面的模式 n 连续出现至少 X 次,至多 Y 次时匹配。例如,/a{1,3}/ 不匹配 “cndy”,匹配 “candy,” 中的 “a”,“caandy,” 中的两个 “a”,匹配 “caaaaaaandy” 中的前面三个 “a”。注意,当匹配 “caaaaaaandy” 时,即使原始字符串拥有更多的 “a”,匹配项也是 “aaa”。 |
n$ | 匹配任何结尾为 n 的字符串。 |
^n | 匹配任何开头为 n 的字符串。 |
?=n | 匹配任何其后紧接指定字符串 n 的字符串。 |
?!n | 匹配任何其后没有紧接指定字符串 n 的字符串。 |
// X? :X,一次或一次也没有
String reg1 = "[a]?"; // 要么是“a”要么什么都没有
System.out.println("aaa".matches(reg1)); // false
// X* :X,零次到多次
String reg2 = "[a]*";
System.out.println("b".matches(reg2)); // false
// X+ :X,一次到 多次
String reg3 = "[a]+";
System.out.println("".matches(reg3)); // false
// X{n} :X,恰好 n 次
String reg4 = "[ab]{3}"; // 内容由a或b组成,长度为3
System.out.println("aaa".matches(reg4)); // true
// X{n,} :X,至少 n 次
// 0次到多次
String reg5 = "[abc]{0,}"; // 内容由a组成,0次到多次!
System.out.println("aaaa".matches(reg5)); // true
// 1次到多次
String reg6 = "[a]{1,}";
System.out.println("".matches(reg6)); // false
// X{n,m} :X,至少 n 次,但是不超过 m 次
String reg7 = "[abc]{2,3}";
System.out.println("abca".matches(reg7)); // false
System.out.println("abc".matches(reg7)); // true
3.5 正则表达式的字符串方法
方法 | 描述 |
---|---|
search | 检索与正则表达式相匹配的值。 |
match | 找到一个或多个正则表达式的匹配。 |
replace | 替换与正则表达式匹配的子串。 |
split | 把字符串分割为字符串数组。 |
字符串分割示例(如下分割每一个打印内容都是都是相同的即为a b c d)
// "a,b,c,d"
String str1 = "a,b,c,d";
String reg1 = "[,]{1}";
String[] strs1 = str1.split(reg1);
for (String str : strs1) {
System.out.println(str);
}
System.out.println("-----------");
// "a,,b,,c,,d"
String str2 = "a,,b,,c,,d";
// String reg2 = ",,";
String reg2 = "[,]{2}";
String[] strs2 = str2.split(reg2);
for (String str : strs2) {
System.out.println(str);
}
System.out.println("-----------");
// "a,b,,c,,,d"
String str3 = "a,b,,c,,,d";
String reg3 = "[,]{1,3}";
String[] strs3 = str3.split(reg3);
for (String str : strs3) {
System.out.println(str);
}
System.out.println("-----------");
// "a,,,,,,,,,b,,,,,,,,,c,,,,,d"
String str4 = "a,,,,,,,,,b,,,,,,,,,c,d";
String reg4 = "[,]+";
String[] strs4 = str4.split(reg4);
for (String str : strs4) {
System.out.println(str);
}
Java Script示例
<script>
var str = "hi66morning77"
// 匹配连续的2个数字 非全局匹配
var reg = /\d{2}/
console.log(str.match(reg)[0]) // 66
// 匹配连续的2个数字 全局匹配(推荐)
var reg2 = /\d{2}/g
console.log(str.match(reg2)) // ["66", "77"]
var str = "hi66morning77"
// 匹配连续的2个数字 非全局匹配
var reg = /\d{2}/
console.log(str.search(reg)) // 2
// 匹配a,b,m中的一个
var reg2 = /[abm]/
console.log(str.search(reg2)) // 4
</script>
3.6 正则表达式的对象
( Pattern和Matcher)模式和匹配器的典型调用顺序如下:
//正则表达式
String reg = "[a]{3}";
//正则表达式 转换为 正则对象
Pattern pattern = Pattern.compile(reg);
//匹配字符串,匹配对象
Matcher matcher = pattern.matcher("aaa");
//开始匹配
boolean flag = matcher.matches();
System.out.println(flag);
3.7 正则表达式校验手机号
需求:把一个字符串中的手机号码获取出来
要求:
- 手机号码共11位
- 开头第一位必须是1
- 第二位必须是356789的其中一位
- 其他9为均为数字(数字的范围即是0~9)
/**
* 手机号码
* 手机号码共11位
* 开头第一位必须是1
* 第二位必须是356789的其中一位
* 其他9为均为数字(数字的范围即是0~9)
*/
String str = "18627775385...fadsfds18627775383..dsfjdsa18627775384";
String reg = "[1]{1}[356789]{1}\\d{9}";
//获取正则对象
Pattern pattern = Pattern.compile(reg);
//获取匹配对象
Matcher matcher = pattern.matcher(str);
//开始查找手机号
//find:在str中找子字符串,子字符串要和正则匹配
List<String> phones = new ArrayList<>();
while (matcher.find()) {
//找到了手机号,获取手机号
String phone = matcher.group();
phones.add(phone);
}
/**
* 遍历打印获取到的手机号码
*/
for (String phone : phones) {
System.out.println(phone);
}
3.8 正则表达式的RegExp对象方法
方法 | 描述 |
---|---|
exec | 检索字符串中指定的值。返回找到的值,并确定其位置。没有发现匹配,则返回 null。 |
test | 检索字符串中指定的值。返回 true 或 false。 |
var patt1 = new RegExp("e");
document.write(patt1.test("The best things in life are free"));
//由于该字符串中存在字母 "e",以上代码的输出将是:true
var patt1 = new RegExp("e");
document.write(patt1.exec("The best things in life are free"));
//由于该字符串中存在字母 "e",以上代码的输出将是:e
四、正则表达式的使用
4.1 正则表达式的简单使用
User实体类+校验
package com.mylifes1110.java.userdemo;
/**
* User实体类+校验
*
* 创建一个User对象,有账号、密码、邮箱
* 账号:数字和字母组成;第一位必须是大写字母;长度范围6~10
* 密码:由数字、字母和_组成;第一位必须是字母;长度为6
* 邮箱:由qq号码、@和.组成;必须是qq邮箱
*/
public class User {
private String username;
private String password;
private String email;
public User() {}
public User(String username, String password, String email) {
if (validateUsername(username)) {
this.username = username;
} else {
throw new MyIllegalArgumentsException("账号输入错误!");
}
if (validatePassword(password)) {
this.password = password;
} else {
throw new MyIllegalArgumentsException("密码输入错误!");
}
if (validateEmail(email)) {
this.email = email;
} else {
throw new MyIllegalArgumentsException("邮箱输入错误!");
}
}
@Override
public String toString() {
return "User{" + "username='" + username + '\'' + ", password='" + password + '\'' + ", email='" + email + '\''
+ '}';
}
/**
* 校验邮箱
* 邮箱:由qq号码、@和.组成;必须是qq邮箱(QQ号码位数是由5位到11位并且没有0开头的QQ号码)
*/
private boolean validateEmail(String email) {
String reg = "[1-9]{5,11}@qq\\.com";
boolean matches = email.matches(reg);
return matches;
}
/**
* 校验密码
* 密码:由数字、字母和_组成;第一位必须是字母;长度为6
*/
private boolean validatePassword(String password) {
String reg = "[a-zA-Z]\\w{5}";
boolean matches = password.matches(reg);
return matches;
}
/**
* 校验账号
* 账号:数字和字母组成;第一位必须是大写字母;长度范围6~10
*/
private boolean validateUsername(String username) {
String reg = "[A-Z][a-zA-Z0-9]{5,9}";
boolean matches = username.matches(reg);
return matches;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
if (validateEmail(email)) {
this.email = email;
} else {
throw new MyIllegalArgumentsException("邮箱输入错误!");
}
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
if (validatePassword(password)) {
this.password = password;
} else {
throw new MyIllegalArgumentsException("密码输入错误!");
}
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
if (validateUsername(username)) {
this.username = username;
} else {
throw new MyIllegalArgumentsException("账号输入错误!");
}
}
}
测试类
package com.mylifes1110.java.userdemo;
import java.util.Scanner;
/**
* 创建一个User对象,有账号、密码、邮箱
* 账号:数字和字母组成;第一位必须是大写字母;长度范围6~10
* 密码:由数字、字母和_组成;第一位必须是字母;长度为6
* 邮箱:由qq号码、@和.组成;必须是qq邮箱
*/
public class UserTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
User user = new User();
System.out.print("请输入账号:");
String username = sc.nextLine();
System.out.print("请输入密码:");
String password = sc.nextLine();
System.out.print("请输入邮箱:");
String email = sc.nextLine();
user.setUsername(username);
user.setPassword(password);
user.setEmail(email);
System.out.println(user);
}
}
自定义异常类
package com.mylifes1110.java.userdemo;
public class MyIllegalArgumentsException extends RuntimeException {
public MyIllegalArgumentsException() {
}
public MyIllegalArgumentsException(String message) {
super(message);
}
public MyIllegalArgumentsException(String message, Throwable cause) {
super(message, cause);
}
public MyIllegalArgumentsException(Throwable cause) {
super(cause);
}
public MyIllegalArgumentsException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
4.2 JavaScript中正则表达式常用校验
匹配手机号
var reg = /^1\d{10}$/;
匹配QQ号
var reg = /^[1-9]\d{4,10}$/;
匹配身份证号
var reg = /^[1-9]\d{16}[Xx\d]$/;
变量名检测(只能由字母,数字,下划线组成,且不能以数字开头,长度6-15)
var reg = /^[A-z_]\w{5,14}$/;
判断是否为邮箱email
验证规则: 电子邮箱的正确写法一般为: 用户名@邮箱网站.com(.cn)
第一部分:由字母、数字、下划线、短线“-”组成
第二部分:为一个域名,域名由字母、数字、短线“-”、域名后缀组成(域名后缀一般为两位到三位。例如:com cn net现在域名有的也会大于四位)
function isEmail(str){
var reg =/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\.[a-zA-Z0-9_-]{2,3}){1,2})$/;
return reg.test(str);
}