正则表达式底层实现
1、不考虑分组
代码示例
public static void main(String args[]){
String content = "2000年5月,JDK1.3、JDK1.4和J2SE1.3相继发布,几周后其获得了Apple公司Mac OS X的工业标准的支持。" +
"2001年9月24日,J2EE1.3发布。2002年2月26日,J2SE1.4发布。自此Java的计算能力有了大幅提升,与J2SE1.3相比," +
"其多了近62%的类和接口。在这些新特性当中,还提供了广泛的XML支持、安全套接字(Socket)支持(通过SSL与TLS协议)、" +
"全新的I/OAPI、正则表达式、日志与断言。2004年9月30日,J2SE1.5发布,成为Java语言发展史上的又一里程碑。为了表示该版本的重要性," +
"J2SE 1.5更名为Java SE 5.0(内部版本号1.5.0),代号为“Tiger”,Tiger包含了从1996年发布1.0版本以来的最重大的更新,其中包括泛型支持、" +
"基本类型的自动装箱、改进的循环、枚举类型、格式化I/O及可变参数。";
// \\d代表一个任意的数字,这段正则匹配的是一个四位的数字
String regStr = "\\d\\d\\d\\d";
// 创建模式对象,即正则表达式对象
Pattern pattern = Pattern.compile(regStr);
// 创建匹配器,按照正则表达式的规则匹配content字符串
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println(matcher.group(0));
}
}
代码解析
①、matcher.find()
-
根据指定的规则,定位满足规则的子字符串(比如content中的第一个匹配结果2000)
-
找到后,将子字符串的开始、结束索引记录到matcher对象的属性 int[] groups 中
groups[0] = 0; 记录的为子字符串开始索引
groups[1] = 4; 记录的为子字符串结束索引 + 1
-
同时记录oldLast的值为子字符串结束索引 + 1,下次执行matcher.find()时,就从oldLast开始匹配
②、matcher.group(0)
// 源码
public String group(int group) {
if (first < 0)
throw new IllegalStateException("No match found");
if (group < 0 || group > groupCount())
throw new IndexOutOfBoundsException("No group " + group);
if ((groups[group*2] == -1) || (groups[group*2+1] == -1))
return null;
return getSubSequence(groups[group * 2], groups[group * 2 + 1]).toString();
}
根据groups[0] = 0 和 groups[1] = 4的记录的位置,从content开始截取字符串返回,就是[0,4),左闭右合,包含索引为0的值,但不包含索引为4的值
2、考虑分组
什么是分组,比如 (\d\d)(\d\d),正则表达式中有(),表示分组,第1个()表示第1组,第2个()表示第2组
代码示例
public static void main(String args[]){
String content = "2000年5月,JDK1.3、JDK1.4和J2SE1.3相继发布,几周后其获得了Apple公司Mac OS X的工业标准的支持。" +
"2001年9月24日,J2EE1.3发布。2002年2月26日,J2SE1.4发布。自此Java的计算能力有了大幅提升,与J2SE1.3相比," +
"其多了近62%的类和接口。在这些新特性当中,还提供了广泛的XML支持、安全套接字(Socket)支持(通过SSL与TLS协议)、" +
"全新的I/OAPI、正则表达式、日志与断言。2004年9月30日,J2SE1.5发布,成为Java语言发展史上的又一里程碑。为了表示该版本的重要性," +
"J2SE 1.5更名为Java SE 5.0(内部版本号1.5.0),代号为“Tiger”,Tiger包含了从1996年发布1.0版本以来的最重大的更新,其中包括泛型支持、" +
"基本类型的自动装箱、改进的循环、枚举类型、格式化I/O及可变参数。";
String regStr = "(\\d\\d)(\\d\\d)";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println(matcher.group(0));
System.out.println(matcher.group(1));
System.out.println(matcher.group(2));
}
}
代码解析
①、matcher.find()
-
根据指定的规则,定位满足规则的子字符串(比如content中的第一个匹配结果2000)
-
找到后,将子字符串的开始、结束索引记录到matcher对象的属性 int[] groups 中
- groups[0] = 0; 记录的为子字符串开始索引 groups[1] = 4; 记录的为子字符串结束索引 + 1
- 记录第1组()匹配到的字符串groups[2] = 0; groups[3] = 2;
- 记录第2组()匹配到的字符串groups[4] = 2; groups[5] = 4;
- 更多的分组…
-
同时记录oldLast的值为子字符串结束索引 + 1,下次执行matcher.find()时,就从oldLast开始匹配
②、matcher.group()
- group(0):表示匹配到的子字符串
- group(1):表示匹配到的子字符串的第1组子串
- group(2):表示匹配到的子字符串的第2组子串
- 更多的分组…
正则表达式语法
元字符
转义符 \\
使用正则表达式去检索某些特殊字符的时候,需要用到转义符号,否则检索不到结果,甚至会报错。
需要用到转义符号的字符有以下:. * + () $ / \ ? [] ^ {}
在Java的正则表达式中,两个\\代表其他语言中的一个\
字符匹配符
符号 | 含义 | 示例 | 说明 | 匹配输入 |
---|---|---|---|---|
[ ] | 可接收的字符列表 | [efgh] | e、f、g、h的任意1个字符 | e、f、g、h |
[^] | 不接收的字符列表 | [^abc] | 除a、b、c之外的任意1个字符,包括数字和特殊符号 | 1、2、$ |
- | 连字符 | A-Z | 任意单个大写字母 | A |
. | 匹配除\n以外的任何字符 | a…b | 以a开头,b结尾,中间包括2个任意字符的字符串 | aaab、aefb、a36b、a#*b |
\\d | 匹配单个数字字符,相当于[0-9] | \\d{3}(\\d)? | 包含3个或4个数字的字符串 | 123、4567 |
\\D | 匹配单个非数字字符,相当于[^0-9] | \\D(\\d)* | 以单个非数字字符开头,后接任意个数字符串 | a、A342 |
\\w | 匹配单个数字、大小写字母字符、下划线,相当于[0-9a-zA-z] | \\d{3}\\w{4} | 以3个数字字符开头的长度为7的数字字母字符串 | 123abcd、12345Pe |
\\W | 匹配单个非数字、大小写字符字符,相当于[^0-9a-zA-Z] | \\W+\\d{2} | 以至少1个非数字字母字符开头,2个数字字符结尾的字符串 | #29、#?@10 |
\\s | 匹配任何空白字符(空格,制表符等) | |||
\\S | 匹配任何非空白字符 |
Java正则表达式默认是区分字母大小写的,如何实现不区分大小写?
- (?i)abc:表示abc都不区分大小写
- a(?i)bc:表示bc不区分大小写
- a((?i)b)c:表示只有b不区分大小写
- Pattern pattern = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE):表示匹配不区分字母大小写
选择匹配符 |
符号 | 含义 | 示例 | 匹配输入 |
---|---|---|---|
| | 匹配 | 之前或之后的表达式 | ab|cd | ab、cd |
限定符
用于指定其前面的字符和组合项连续出现多少次
符号 | 含义 | 示例 | 说明 | 匹配输入 |
---|---|---|---|---|
* | 指定字符重复0次或n次(无要求)零到多 | (abc)* | 仅包含任意个abc的字符串 | abc、abcabcabc |
+ | 指定字符重复1次或n次(至少一次)一到多 | m+(abc)* | 以至少1个m开头,后接任意个abc的字符 | m、mabc、mabcabc |
? | 指定字符重复0次或1次(最多一次)零到一 | m+abc? | 以至少1个m开头,后接ab或abc的字符串 | mab、mabc、mmmab、mmabc |
{n} | 只能输入n个字符 | [abcd]{3} | 由abcd中字母组成的任意长度为3的字符串 | abc、dbc、adc |
{n,} | 指定至少n个匹配 | [abcd]{3,} | 由abcd中字母组成的任意长度不小于3的字符串 | aab、dbc、aaabdc |
{n,m} | 指定至少n个但不多于m个匹配 | [abcd]{3,5} | 由abcd中字母组成的任意长度不小于3,不大于5的字符串 | abc、abcd、aaaaa、bcdab |
非贪婪匹配:当?紧随其他限定符(*、+、?、{n}、{n,}、{n.m})之后,匹配模式是非贪婪匹配,会匹配尽可能短的字符串,而默认的贪婪匹配会匹配尽可能长的字符串。
定位符
定位符规定要匹配的字符串出现的位置,比如在字符串的开始还是结束的位置
符号 | 含义 | 示例 | 说明 | 匹配输入 |
---|---|---|---|---|
^ | 指定起始字符 | ^ [0-9]+[a-z]* | 以至少一个数字开头,后接任意个小写字符的字符串 | 123、123abc |
$ | 指定结束字符 | ^ [0-9]\-[a-z]+$ | 以一个数字开头,后接连字符-,并以至少一个小写字母结尾的字符串 | 1-a |
\\b | 匹配目标字符串的边界 | han\\b | 这里说的是字符串的边界指的是子串间有空格,或者是目标字符串的结束位置 | sphan |
\\B | 匹配目标字符串的非边界 | han\\B | 和\\b的含义刚刚相反 | hanshunping |
分组
捕获分组
分组构造形式 | 说明 |
---|---|
(pattern) | 非命名捕获,捕获匹配的子字符串,编号为零的第一个捕获是由整个正则表达式模式匹配的文本,其他捕获结果则根据左括号的顺序从1开始自动编号 |
(?pattern) | 命名捕获,将匹配的子字符串捕获到一个组名或编号名称中。用于name的字符串不能包含任何标点符号,并且不能以数字开头。可以使用单引号替代尖括号,例如(?‘name’) |
public static void main(String[] args) {
// 1、非命名捕获
String content = "秦朝(前221年—前207年),是中国历史上第一个统一的封建王朝";
String regStr = "(\\d\\d)(\\d)";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println(matcher.group(0));
System.out.println("\t分组1:" + matcher.group(1));
System.out.println("\t分组2:" + matcher.group(2));
}
}
public static void main(String[] args) {
// 2、命名捕获
String content = "秦朝(前221年—前207年),是中国历史上第一个统一的封建王朝";
String regStr = "(?<g1>\\d\\d)(?<g2>\\d)";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println(matcher.group(0));
System.out.println("\t分组1:" + matcher.group(1));
System.out.println("\t分组1:" + matcher.group("g1"));
System.out.println("\t分组2:" + matcher.group(2));
System.out.println("\t分组2:" + matcher.group("g2"));
}
}
非捕获分组
分组构造形式 | 说明 |
---|---|
(?:pattern) | 匹配pattern但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用“or”字符(|)组合模式部件的情况很有用,例如,'industr(?:y|ies)'是比’industry|industries’更经济的表达式 |
(?=pattern) | 它是一个非捕获匹配。例如,'Windows(?=95|NT|2000)'匹配’Windows 2000’中的"Windows",但不匹配"Windows 3.1"中的"Windows" |
(?!pattern) | 该表达式匹配不处于匹配pattern的字符串的起始点的搜索字符串,它是一个非捕获匹配。例如,“Windows(?!95|98|NT|2000)“匹配"Windows 3.1"中的"Windows”,但不匹配"Windows 2000"中的"Windows” |
public static void main(String[] args) {
// 1、(?:pattern)
String content = "迪迦奥特曼,戴拿奥特曼,盖亚奥特曼,阿古茹奥特曼";
// 等效于(迪迦奥特曼|戴拿奥特曼|盖亚奥特曼|阿古茹奥特曼)
// String regStr = "(迪迦奥特曼|戴拿奥特曼|盖亚奥特曼|阿古茹奥特曼)";
String regStr = "(?:迪迦|戴拿|盖亚|阿古茹)奥特曼";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println(matcher.group(0));
}
}
public static void main(String[] args) {
// 2、(?=pattern) 零宽正向先行断言
String content = "奥特曼迪迦,奥特曼戴拿,奥特曼盖亚,奥特曼阿古茹";
String regStr = "奥特曼(?=迪迦|戴拿|盖亚|阿古茹)";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println(matcher.group(0));
}
}
public static void main(String[] args) {
// 3、(?!pattern) 负向先行断言
String content = "奥特曼迪迦,奥特曼戴拿,奥特曼盖亚,奥特曼阿古茹";
String regStr = "奥特曼(?!阿古茹)";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println(matcher.group(0));
}
}
正则表达式三个常用类
java.util.regex包主要包括以下三个类
-
Pattern
Pattern对象是一个正则表达式对象。Pattern类没有公共构造方法。要创建一个Pattern对象需要调用其公共静态方法compile,它返回一个Pattern对象,该方法接收一个正则表达式作为它的参数。
比如:Pattern pattern = Pattern.compile(pattern);
-
Matcher
Matcher对象是对输入字符串进行解释和匹配的引擎。与Pattern类一样,Matcher也没有公共构造方法,需要调用Pattern对象的matcher方法来获得一个Matcher对象,该方法接收一个文本内容作为其参数。
比如:Matcher matcher = pattern.matcher(content);
-
PatternSyntaxException
PatternSyntaxException是一个非强制异常类,它表示一个正则表达式模式中的语法错误。
常用方法
Pattern.matches
该方法接收两个参数,第一个参数为正则表达式,第二个参数为需要匹配的内容。用于检测字符串是否匹配给定的正则表达式。
package com.example;
import java.util.regex.Pattern;
/**
* @Description Pattern.matches
* @CreateTime 2024/3/22 18:11
* @Author dyf
*/
public class PatternMethod {
public static void main(String[] args) {
String content = "落霞与孤鹜齐飞,秋水共长天一色";
String regStr = ".*秋水.*";
boolean isMatch = Pattern.matches(regStr, content);
System.out.println("是否匹配成功: " + isMatch);
}
}
该方法底层调用的是Matcher类的matches方法
public static boolean matches(String regex, CharSequence input) { Pattern p = Pattern.compile(regex); Matcher m = p.matcher(input); return m.matches(); }
Matcher类
public int start()
:返回以前匹配的初始索引public int start(int group)
:返回再以前的匹配操作期间,由给定组所捕获的子序列的初始索引public int end()
:返回最后匹配字符之后的偏移量public int end(int group)
:返回在以前的匹配操作期间,由给定组所捕获子序列的最后字符之后的偏移量public boolean lookingAt()
:尝试将从区域开头开始的输入序列与该模式匹配public boolean find()
:尝试查找与该模式匹配的输入序列的下一个子序列public boolean find(int start)
:重置此匹配器,然后尝试查找匹配该模式、从指定索引开始的输入序列的下一个子序列public boolean matches()
:尝试将整个区域与模式匹配public Matcher appendReplacement(StringBuffer sb, String replacement)
:实现非终端添加和替换步骤public StringBuffer appendTail(StringBuffer sb)
:实现终端添加和替换步骤public String replaceAll(String replacement)
:替换模式与给定替换字符串相匹配的输入序列的每个子序列public String replaceFirst(String replacement)
:替换模式与给定替换字符串匹配的输入序列的第一个子序列public static String quoteReplacement(String s)
:返回指定字符串的字面替换字符串,这个方法返回一个字符串,就像传递给Matcher类的appendReplacement方法一个字面字符串一样工作public Matcher appendReplacement(String Buffer sb, String replacement)
:实现非终端添加和替换步骤
反向引用
分组捕获后,可以在后面被使用,从而编写出一个比较实用的匹配模式,称之为反向引用。这种引用既可以是在正则表达式内部,也可以是在正则表达式外部,内部反向引用\\分组号
,外部反向引用$分组号
案例
1、匹配两个连续的相同数字
2、匹配五个连续的相同数字
3、匹配个位与千位相同,十位与百位相同的数字
4、请在字符串中检索商品编号,形式如:12321-333999111 这样的号码,要求满足前面是一个五位数,然后一个-号,然后是一个九位数,连续的每三位要相同
package com.example;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Description TODO
* @CreateTime 2024/3/22 21:17
* @Author dyf
*/
public class RegExp04 {
public static void main(String[] args) {
/*
1、匹配两个连续的相同数字
2、匹配五个连续的相同数字
3、匹配个位与千位相同,十位与百位相同的数字
4、在字符串中检索商品编号,形式如:12321-333999111 这样的号码,要求满足前面是一个五位数,然后一个-号,然后是一个九位数,连续的每三位要相同
*/
// String content = "11";
// String regStr = "(\\d)\\1";
// String content = "11111";
// String regStr = "(\\d)\\1{4}";
// String content = "1212";
// String regStr = "(\\d)(\\d)\\1\\2";
String content = "12321-333999111";
String regStr = "\\d{5}-(\\d)\\1{2}(\\d)\\2{2}(\\d)\\3{2}";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println(matcher.group());
}
}
}
String类中使用正则表达式
替换功能
public String replaceAll(String regex, String replacement)
package com.example;
/**
* @Description TODO
* @CreateTime 2024/3/22 22:13
* @Author dyf
*/
public class RegExp06 {
public static void main(String[] args) {
String content = "迪迦,戴拿,盖亚";
content = content.replaceAll("戴拿|盖亚", "迪迦");
System.out.println(content);
}
}
判断功能
public boolean matches(String regex)
package com.example;
/**
* @Description TODO
* @CreateTime 2024/3/22 22:17
* @Author dyf
*/
public class RegExp07 {
public static void main(String[] args) {
// 验证一个手机号,要求必须是以138、139开头的
String phone = "13879450636";
boolean matches = phone.matches("^13[89]\\d{8}");
System.out.println(matches);
}
}
分割功能
public String[] split(String regex)
package com.example;
/**
* @Description TODO
* @CreateTime 2024/3/22 22:23
* @Author dyf
*/
public class RegExp08 {
public static void main(String[] args) {
// 要求按照 # 或者 - 或者 ~ 或者 数字 来分割
String content = "hello##abc-jack12smith~北京";
String[] split = content.split("(#|-|~|\\d)+");
for (String s : split) {
System.out.println(s);
}
}
}
练习
验证是否是汉字
package com.example;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Description 验证是否是汉字
* @CreateTime 2024/3/11 15:12
* @Author dyf
*/
public class RegExpTest01 {
public static void main(String[] args) {
String regStr = "^[\u4E00-\u9FA5]+$";
String content = "秦朝建立于公元前年";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
if (matcher.find()) {
System.out.println(matcher.group());
}
}
}
验证是否邮政编码
package com.example;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Description 验证是否邮政编码 要求:1-9开头的一个六位数 比如:123890
* @CreateTime 2024/3/11 15:12
* @Author dyf
*/
public class RegExpTest02 {
public static void main(String[] args) {
String regStr = "^[1-9]\\d{5}$";
String content = "123890";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
if (matcher.find()) {
System.out.println(matcher.group() + "符合格式");
} else {
System.out.println("不符合格式");
}
}
}
验证是否是QQ号码
package com.example;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Description 验证是否是QQ号码 要求:是1-9开头的一个(5位-10位数)
* @CreateTime 2024/3/11 15:12
* @Author dyf
*/
public class RegExpTest03 {
public static void main(String[] args) {
String regStr = "^[1-9]\\d{4,9}$";
String content = "1179678168";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
if (matcher.find()) {
System.out.println(matcher.group() + "符合格式");
} else {
System.out.println("不符合格式");
}
}
}
验证是否是手机号码
package com.example;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Description 验证是否是手机号码 要求:必须以13、14、15、17、18开头的11位数
* @CreateTime 2024/3/11 15:12
* @Author dyf
*/
public class RegExpTest04 {
public static void main(String[] args) {
String regStr = "^1[34578]\\d{9}$";
String content = "12279450636";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
if (matcher.find()) {
System.out.println(matcher.group() + "符合格式");
} else {
System.out.println("不符合格式");
}
}
}
验证是否是URL
package com.example;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Description 验证是否是URL
* @CreateTime 2024/3/11 15:12
* @Author dyf
*/
public class RegExpTest05 {
public static void main(String[] args) {
/**
* 1、^((http|https)://)匹配URL开头
* 2、([\w-]+\.)+[\w-]+匹配 www.bilibili.com
* 3、/[\w-?/=#.&%]*$ 匹配结尾
*/
String regStr = "^((http|https)://)([\\w-]+\\.)+[\\w-]+/[\\w-?/=#.&%]*$";
String content = "https://njuics.github.io/OnJava8/#/book/01-What-is-an-Object?id=%e6%8a%bd%e8%b1%a1";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
if (matcher.find()) {
System.out.println(matcher.group() + "符合格式");
} else {
System.out.println("不符合格式");
}
}
}
结巴程序
package com.example;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Description 结巴程序
* @CreateTime 2024/3/22 21:52
* @Author dyf
*/
public class RegExp05 {
public static void main(String[] args) {
// 把类似:"我....我要....学学学学....编程Java!" 通过正则表达式,修改成 "我要学编程Java"
String content = "我....我要....学学学学....编程Java!";
String regStr = "\\.";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
content = matcher.replaceAll("");
System.out.println(content);
regStr = "(.)\\1+";
pattern = Pattern.compile(regStr);
matcher = pattern.matcher(content);
content = matcher.replaceAll("$1");
System.out.println(content);
}
}
验证电子邮件格式是否合法
package com.example;
/**
* @Description 验证电子邮件格式是否合法
* @CreateTime 2024/3/22 22:28
* @Author dyf
*/
public class HomeWork01 {
public static void main(String[] args) {
/*
规定电子邮件规则为:
1、只能有一个@
2、@前面是用户名,可以是a-z A-Z 0-9 -字符
3、@后面是域名,并且域名只能是英文字母,比如 qq.com 或者 tsinghua.org.cn
*/
String email = "1179@tsinghua.org.cn";
String regxStr = "^[\\w-]+@([a-zA-Z]+\\.)+[a-zA-Z]+$";
boolean matches = email.matches(regxStr);
System.out.println(matches);
}
}
验证是不是整数或者小数
package com.example;
/**
* @Description 验证是不是整数或者小数
* @CreateTime 2024/3/22 22:41
* @Author dyf
*/
public class HomeWork2 {
public static void main(String[] args) {
// 提示:这个题要考虑正数和负数
// 比如:123 -345 34.89 -87.9 -0.01 0.45等
String content = "0.45";
String regx = "^[+-]?([1-9]\\d*|0)(\\.\\d+)?$";
System.out.println(content.matches(regx));
}
}
解析URL
package com.example;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Description 解析URL
* @CreateTime 2024/3/22 22:50
* @Author dyf
*/
public class HomeWork03 {
public static void main(String[] args) {
/*
https://www.bilibili.com:8080/video/index.html
1、要求得到协议是什么 https
2、域名是什么 www.bilibili.com
3、端口是什么 8080
4、文件名是什么 index.html
*/
String content = "https://www.bilibili.com:8080/video/index.html";
String regxStr = "^([a-zA-Z]+)://([a-zA-Z.]+):(\\d+)[\\w-/]*/([\\w.]+)$";
Pattern pattern = Pattern.compile(regxStr);
Matcher matcher = pattern.matcher(content);
if (matcher.find()) {
System.out.println("协议:" + matcher.group(1));
System.out.println("域名:" + matcher.group(2));
System.out.println("端口:" + matcher.group(3));
System.out.println("文件名:" + matcher.group(4));
}
}
}
常用正则表达式
一、校验数字的表达式
数字:^[0-9]*$
n位的数字:^\d{n}$
至少n位的数字:^\d{n,}$
m-n位的数字:^\d{m,n}$
零和非零开头的数字:^(0|[1-9][0-9]*)$
非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$
带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})?$
正数、负数、和小数:^(\-|\+)?\d+(\.\d+)?$
有两位小数的正实数:^[0-9]+(.[0-9]{2})?$
有1~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$
非零的正整数:^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$
非零的负整数:^\-[1-9][]0-9"*$ 或 ^-[1-9]\d*$
非负整数:^\d+$ 或 ^[1-9]\d*|0$
非正整数:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$
非负浮点数:^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$
非正浮点数:^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
正浮点数:^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
负浮点数:^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
浮点数:^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$
二、校验字符的表达式
汉字:^[\u4e00-\u9fa5]{0,}$
英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
长度为3-20的所有字符:^.{3,20}$
由26个英文字母组成的字符串:^[A-Za-z]+$
由26个大写英文字母组成的字符串:^[A-Z]+$
由26个小写英文字母组成的字符串:^[a-z]+$
由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
由数字、26个英文字母或者下划线组成的字符串:^\w+$ 或 ^\w{3,20}$
中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$
中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
可以输入含有^%&',;=?$\"等字符:[^%&',;=?$\x22]+
禁止输入含有~的字符:[^~\x22]+
三、特殊需求表达式
Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
手机号码:^(13[0-9]|14[0-9]|15[0-9]|16[0-9]|17[0-9]|18[0-9]|19[0-9])\d{8}$ (由于工信部放号段不定时,所以建议使用泛解析 ^([1][3,4,5,6,7,8,9])\d{9}$)
电话号码("XXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"和"XXXXXXXX):^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$
国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
18位身份证号码(数字、字母x结尾):^((\d{18})|([0-9x]{18})|([0-9X]{18}))$
帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
日期格式:^\d{4}-\d{1,2}-\d{1,2}
一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$
一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$
钱的输入格式:
1.有四种钱的表示形式我们可以接受:"10000.00" 和 "10,000.00", 和没有 "分" 的 "10000" 和 "10,000":^[1-9][0-9]*$
2.这表示任意一个不以0开头的数字,但是,这也意味着一个字符"0"不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$
3.一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$
4.这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$
5.必须说明的是,小数点后面至少应该有1位数,所以"10."是不通过的,但是 "10" 和 "10.2" 是通过的:^[0-9]+(.[0-9]{2})?$
6.这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$
7.这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$
8.1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$
备注:这就是最终结果了,别忘了"+"可以用"*"替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里
xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$
中文字符的正则表达式:[\u4e00-\u9fa5]
双字节字符:[^\x00-\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
空白行的正则表达式:\n\s*\r (可以用来删除空白行)
HTML标记的正则表达式:<(\S*?)[^>]*>.*?</\1>|<.*? /> (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)
首尾空白字符的正则表达式:^\s*|\s*$或(^\s*)|(\s*$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)
中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)
IP地址:\d+\.\d+\.\d+\.\d+ (提取IP地址时有用)
IP地址:((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))
笔记内容来源:韩顺平老师的课程
常用正则表达式来源:https://www.cnblogs.com/zxin/archive/2013/01/26/2877765.html