概述:描述了一种字符串匹配的模式,用来检查一个串是否含有某个子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。
应用场景:邮箱、IP格式等的验证处理,复杂字符串的内容替换或修改处理等。
由Java.util.regex开发包中Pattern程序类定义,这里参考JDK6.0的API文档,列举出了常用的基本符号。
1.1 字符元字符 | 描述 |
---|---|
x | 字符x |
\\ | 反斜线字符 |
\t | 制表符 |
\n | 换行符 |
\r | 回车符 |
\f | 换页符 |
元字符 | 描述 |
---|---|
[abc] | a、b或c中任意一个字符(简单类) |
[^abc] | 除了 a、b、c的任意一个字符(否定) |
[a-zA-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 && [a-lq-z] ] = [a-lq-z](减去) |
元字符 | 描述 |
---|---|
. | 任何字符(与行结束符可能匹配也可能不匹配) |
\d | 数字:[0-9] |
\D | 非数字: [^0-9] |
\s | 空白字符(空格,换行,制表符等):[ \t\n\x0B\f\r] |
\S | 非空白字符:[^\s] |
\w | 单词字符:[a-zA-Z_0-9] |
\W | 非单词字符:[^\w] |
元字符 | 描述 |
---|---|
^ | 行的开头 |
$ | 行的结尾 |
元字符 | 描述 |
---|---|
X? | X,一次或一次也没有 |
X* | X,零次或多次 |
X+ | X,一次或多次 |
X{n} | X,恰好 n 次 |
X{n,} | X,至少 n 次 |
X{n,m} | X,至少 n 次,但是不超过 m 次 |
元字符 | 描述 |
---|---|
XY | X 后跟 Y |
X|Y | X 或 Y |
(X) | X,作为捕获组(分组匹配可用到) |
1)在JDK1.4之后,正则已经默认被JDK支持,不用导入其他的*.jar 包;
2)正则表达式大部分处理情况都会基于String类来完成;
3)String类对正则的支持满足拆分、替换、匹配三种操作。
描述 | 方法 |
---|---|
将指定字符串进行正则判断 | public Boolean matches(String regex) |
替换全部 | public String replaceAll(String regex , String replacement) |
替换首个 | public String replaceFirst(String regex , String replacement) |
正则拆分 | public String[] split(String regex) |
正则拆分(添加应用次数) | public String[] split(String regex , int limit) |
如果纯粹的是以拆分、替换、匹配三种操作为例根本用不到 java.util.regex开发包,只依靠 String类就都可以实现了。但是Java.util.regex包可以进行一些更为复杂的正则处理,如:匹配分组,多次匹配等操作。
Java.util.regex包提供有Pattern、Mather两个类。Pattern类进行正则表达式的编译,而Matcher类进行正则匹配,可将两者搭配起来进行复杂的正则处理。
描述 | 方法 |
---|---|
正则表达式的编译处理 | public static Pattern compile(String regex)(静态方法,可预编译提高效率) |
拆分 | public String[] split(CharSequence input) |
匹配 | public Matcher matcher(CharSequence input) |
编译加匹配 | public static boolean matches(String regex,CharSequence input) |
描述 | 方法 |
---|---|
对整个字符串进行匹配 | public boolean matches() |
对字符串开头进行匹配 | public boolean lookingAt() |
对字符串任意位置进行匹配 | public boolean find() |
匹配字符串在母串中的index | public int start() |
匹配字符串的最后一个字符在母串中的index+1 | public int end() |
匹配到的字符串 | public String group() |
1)在执行过上述返回boolean值的方法之后,可以执行m.start()、m.end()、m.group()返回匹配细节。
2)start、end和group方法也可以用参数指定获取哪个分组的细节,整个模式自身算是第0个分组。
String str1 = "abc123456_7@qq.com";
String str2 = "_Abc1234567@qq.com";
String regex = "[a-zA-Z0-9]\\w+@\\w+\\.(cn|com|com.cn|net|gov)";
System.out.println(str1.matches(regex)+" "+str2.matches(regex));
//str1返回true,str2返回false。
//[a-zA-Z0-9]表示大小写字母和数字中任意一个字符,\w表示字母数字下划线的任意一个,表达式后面有个加号表示多个,(cn|com|com.cn|net|gov)表示满足一个即可。
4.2 SQL语句内容抽取
String str = "INSERT INTO dept(deptno,dname,loc) VALUES (#{deptno},#{dname},#{loc})";
String regex = "#\\{\\w+\\}";
Pattern pat = Pattern.compile(regex);//编译
Matcher mat = pat.matcher(str);
while(mat.find()){//是否有匹配成功的内容
System.out.println(mat.group(0).replaceAll("#|\\{|\\}", "")+" ");//替换,去掉#{}并输出
}
//内容输出为deptno dname loc
4.3 数字验证
String regex6="[+|-]?\\d+(\\.\\d+)?([e|E][+|-]?\\d+)?";
System.out.println(isNumber("+-123",regex6));//false
System.out.println(isNumber("-123",regex6));//true
System.out.println(isNumber("+123",regex6));//true
System.out.println(isNumber("123",regex6));//true
System.out.println(isNumber("5.6e2",regex6));//true
System.out.println(isNumber("-1E-23",regex6));//true
System.out.println(isNumber("3.1415",regex6));//true
System.out.println(isNumber("3.1415e8990",regex6));//true
System.out.println(isNumber("3.1415e89.90",regex6));//false
public static boolean isNumber(String str,String regex){
return str.matches(regex);
}
4.4 匹配分组加多次匹配
String str="AA[BB[CCDD[EEFFGG[HH]]]]";
String regex="([A-Z]+)\\[([A-Z]+)\\]";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
while(matcher.find()){
String temp = "";
for (int i = 1; i <= matcher.groupCount(); i++) {
System.out.print(matcher.group(i)+" ");
temp = temp + matcher.group(i);
}System.out.println();
str = matcher.replaceAll(temp);
matcher = pattern.matcher(str);
}
/*
* 运行结果:
* EEFFGG HH
CCDD EEFFGGHH
BB CCDDEEFFGGHH
AA BBCCDDEEFFGGHH
*/
5. 真题
5.1 压缩算法
腾讯2020校园招聘-后台
小Q想要给他的朋友发送一个神秘字符串,但是他发现字符串的过于长了,于是小Q发明了一种压缩算法对字符串中重复的部分进行了压缩,对于字符串中连续的m个相同字符串S将会压缩为[m|S](m为一个整数且1<=m<=100),例如字符串ABCABCABC将会被压缩为[3|ABC],现在小Q的同学收到了小Q发送过来的字符串,你能帮助他进行解压缩么?
输入描述:
输入第一行包含一个字符串s,代表压缩后的字符串。
S的长度<=1000;
S仅包含大写字母、[、]、|;
解压后的字符串长度不超过100000;
压缩递归层数不超过10层;
输出描述:
输出一个字符串,代表解压后的字符串。
输入例子1:
HG[3|B[2|CA]]F
输出例子1:
HGBCACABCACABCACAF
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
static String regex = "\\[(\\d+)\\|(\\w+)\\]";
static Pattern pattern = Pattern.compile(regex);
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String s = scanner.next();
Matcher matcher = pattern.matcher(s);
while (matcher.find()) {
// System.out.print(matcher.group(1) + " " + matcher.group(2) +
// " ");//分组、括号()是关键
int num = Integer.parseInt(matcher.group(1));
String temp = "";
for (int i = 0; i < num; i++) {
temp += matcher.group(2);
}
s = matcher.replaceAll(temp);
// System.out.println(s);
matcher = pattern.matcher(s);
}
System.out.println(s);
}
}
5.2 音节判断
2020年蓝桥杯模拟赛解题报告
【问题描述】小明对类似于 hello 这种单词非常感兴趣,这种单词可以正好分为四段,第一段由一个或多个辅音字母组成,第二段由一个或多个元音字母组成,第三段由一个或多个辅音字母组成,第四段由一个或多个元音字母组成。给定一个单词,请判断这个单词是否也是这种单词,如果是请输出yes,否则请输出no。元音字母包括 a, e, i, o, u,共五个,其他均为辅音字母。
【输入格式】输入一行,包含一个单词,单词中只包含小写英文字母。
【输出格式】输出答案,或者为yes,或者为no。
【样例输入】lanqiao
【样例输出】yes
【样例输入】world
【样例输出】no
【评测用例规模与约定】对于所有评测用例,单词中的字母个数不超过100。
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public Main {
static Pattern p = Pattern.compile("[^aeiou]+[aeiou]+[^aeiou]+[aeiou]+");
static Scanner sc = new Scanner(System.in);
public static void main(String[] args) {
while (true) { //死循环是为了测试
if (work())
System.out.println("yes");
else
System.out.println("no");
}
}
static boolean work() {
String word = sc.nextLine();
Matcher m = p.matcher(word);
return m.matches();
}
}
5.3 正则表达式匹配(剑指Offer 面试题19)
请实现一个函数用来匹配包括 ‘.’ 和 ‘*’ 的正则表达式。模式中的字符 ‘.’ 表示任意一个字符,而 ‘*’ 表示它前面的字符可以出现任意次(包含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配。
public class Main {
public static void main(String[] args) {
System.out.println(matchCore("aaa", "a.a", 0, 0)); // true
System.out.println(matchCore("aaa", "ab*ac*a", 0, 0)); // true
System.out.println(matchCore("aaa", "aa.a", 0, 0)); // false
System.out.println(matchCore("aaa", "ab*a", 0, 0)); // false
System.out.println(matchCore("aaa", "*a.a", 0, 0)); // false
}
public static boolean matchCore(String str, String regex, int sIndex, int rIndex) {
int slen = str.length();
int rlen = regex.length();
// 同时遍历完才算成功
if (sIndex == slen && rIndex == rlen) {
return true;
}
if (sIndex == slen && rIndex != rlen) {
return false;
}
if (sIndex != slen && rIndex == rlen) {
return false;
}
// 第二个字符为‘*’的情况
if (rIndex + 1 < rlen && regex.charAt(rIndex + 1) == '*') {
if (regex.charAt(rIndex) == str.charAt(sIndex)
|| (regex.charAt(rIndex) == '.' && sIndex < slen)) {
return matchCore(str, regex, sIndex + 1, rIndex + 2) // ‘*’为1
|| matchCore(str, regex, sIndex + 1, rIndex) // ‘*’为n
|| matchCore(str, regex, sIndex, rIndex + 2); // ‘*’为0
} else {
return matchCore(str, regex, sIndex, rIndex + 2);
}
}
if (regex.charAt(rIndex) == str.charAt(sIndex)
|| (regex.charAt(rIndex) == '.' && sIndex < slen)) {
return matchCore(str, regex, sIndex + 1, rIndex + 1);
}
return false;
}
}