Java中正则表达式处理
正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。
1、所有的正则表达式都是以^ 开头, 以$结尾。 2、反斜线\在Java中使用特殊用途的,所以。不要直接使用\反斜线。如果想使用反斜线请使用\\ 因为有些字符是需要表达特别含义的,所以Java用\ 作为转义字符,比如\n,在Java中表示换行。所以使用反斜线则需要转义故而形式为\\ 3、? 代表匹配某个模式的0个字符或者1个字符 比如,我想匹配的data后面的字符是一个数字,这个数字可以不出现,但是只能出现1次。 public class RegularTest {
@Test
public void testRegex(){
String regex = "^data\\d?$";
String value1 = "data";
String value2 = "data1";
String value3 = "data2";
String value4 = "data3";
String value5 = "data33";
System.out.println(Pattern.matches(regex, value1));
System.out.println(Pattern.matches(regex, value2));
System.out.println(Pattern.matches(regex, value3));
System.out.println(Pattern.matches(regex, value4));
System.out.println(Pattern.matches(regex, value5));
//true
//true
//true
//true
//false
}
}
4、* 代表匹配某个模式0个或者多个字符。他在? 基础上,增强了。 比如我想能匹配多个数字字符。 public class RegularTest {
@Test
public void testRegex(){
String regex = "^data\\d*$";
String value1 = "data";
String value2 = "data1";
String value3 = "data2";
String value4 = "data3";
String value5 = "data33";
String value6 = "data334";
String value7 = "datab";
System.out.println(Pattern.matches(regex, value1));
System.out.println(Pattern.matches(regex, value2));
System.out.println(Pattern.matches(regex, value3));
System.out.println(Pattern.matches(regex, value4));
System.out.println(Pattern.matches(regex, value5));
System.out.println(Pattern.matches(regex, value6));
System.out.println(Pattern.matches(regex, value7));
//true
//true
//true
//true
//true
//true
//false
}
}
5、+ 代表此模式,必须出现一次。
比如* 比较,这个模式不出现则为false.
public class RegularTest {
@Test
public void testRegex(){
String regex = "^data\\d+$";
String value1 = "data";
String value2 = "data1";
String value3 = "data2";
String value4 = "data3";
String value5 = "data33";
String value6 = "data334";
String value7 = "datab";
System.out.println(Pattern.matches(regex, value1));
System.out.println(Pattern.matches(regex, value2));
System.out.println(Pattern.matches(regex, value3));
System.out.println(Pattern.matches(regex, value4));
System.out.println(Pattern.matches(regex, value5));
System.out.println(Pattern.matches(regex, value6));
System.out.println(Pattern.matches(regex, value7));
//false
//true
//true
//true
//true
//true
//false
}
}
这种我们称为限定符,用于规定给定组件必须要出现多少次才能满足匹配的。限定表总结如下:
字符描述*匹配前面的子表达式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”*。** 等价于 {0,}。+匹配前面的子表达式一次或多次。例如,zo+ 能匹配 “zo” 以及 "zoo",但不能匹配 “z”*。*+ 等价于 {1,}。?匹配前面的子表达式零次或一次。例如,do(es)? 可以匹配 “do” 、 “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?。请注意在逗号和两个数之间不能有空格。
如果我们想要表示一个范围内的字符,可以使用方括号:
public static void main(String[] args) {
String str = "abcabccaa";
System.out.println(str.matches("[abc]*")); //表示abc这几个字符可以出现 0 - N 次
}
对于普通字符来说,我们可以下面的方式实现多种字符匹配:
字符描述[ABC]匹配 […] 中的所有字符,例如 [aeiou] 匹配字符串 “google runoob taobao” 中所有的 e o u a 字母。[^ABC]匹配除了 […] 中字符的所有字符,例如 [^aeiou] 匹配字符串 “google runoob taobao” 中除了 e o u a 字母的所有字母。[A-Z][A-Z] 表示一个区间,匹配所有大写字母,[a-z] 表示所有小写字母。.匹配除换行符(\n、\r)之外的任何单个字符,相等于 [^\n\r][\s\S]匹配所有。\s 是匹配所有空白符,包括换行,\S 非空白符,不包括换行。\w匹配字母、数字、下划线。等价于 [A-Za-z0-9_]
当然,这里仅仅是对正则表达式的简单使用,实际上正则表达式内容非常多,如果需要完整学习正则表达式,可以到:https://www.runoob.com/regexp/regexp-syntax.html
正则表达式并不是只有Java才支持,其他很多语言比如JavaScript、Python等等都是支持正则表达式的。
Parttern
Java提供了Parttern 对我们输入的正则表达式进行一个封装处理,调用compile()编译方法就可以完成对正则的封装。
compile
public class PatternTest {
@Test
public void compile(){
Pattern pattern1 = Pattern.compile("[a-z]");
Pattern pattern2 = Pattern.compile("[A-Z]");
Pattern pattern3 = Pattern.compile("\\d");
}
}
matcher
定义好正则匹配对象后,调用matcher() 将需要校验字符串注入,返回一个校验结果的Matcher 对象。
public class PatternTest {
@Test
public void matcher() {
Pattern pattern1 = Pattern.compile("[a-z]");
String newcheckStr = "1111";
//执行匹配,结果封装到Matcher对象中
Matcher matcher = pattern1.matcher(newcheckStr);
}
}
Matcher
find
校验结果对象Matcher的find()方法可以获取到本次校验结果,校验通过返回true 校验不通过返回false
public class MatchResultTest {
@Test
public void find() {
//校验
Pattern pattern1 = Pattern.compile("[a-z]");
String newCheckStr = "1111";
Matcher matcher = pattern1.matcher(newCheckStr);
//获取本此校验结果
boolean validResult = matcher.find();
System.out.println(validResult);
}
}
toMatchResult
通过Pattern,对输入的字符串进行匹配,得到匹配器实例Matcher,可以通过find()方法判断是否匹配上。如果匹配上,可以通过toMatchResult得到匹配结果值。
package com.wnx.naizi;
import org.junit.jupiter.api.Test;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MatchResultTest {
@Test
public void toMatchResult() {
//匹配${}的正则
Pattern pattern = Pattern.compile("\\$\\{(.*?)\\}");
String input = "我的名字是${name},手机号${phone},地址${address}";
Matcher matcher = pattern.matcher(input);
//获取匹配结果值
while (matcher.find()){
MatchResult matchResult = matcher.toMatchResult();
System.out.println(matchResult.group());
}
//${name}
//${phone}
//${address}
}
}
start&end
获取匹配到的子串在input的开始下标的终止下标。
public class MatchResultTest {
@Test
public void toMatchResult() {
//匹配${}的正则
Pattern pattern = Pattern.compile("\\$\\{(.*?)\\}");
String input = "我的名字是${name},手机号${phone},地址${address}";
Matcher matcher = pattern.matcher(input);
//获取匹配结果值
while (matcher.find()){
MatchResult matchResult = matcher.toMatchResult();
System.out.println(matchResult.group());
System.out.println(matchResult.start());
System.out.println(matchResult.end());
}
}
}
group
简介 最近在做一个项目,需要使用matcher.group()方法匹配出需要的内容
java.time.MatchResult.group()方法返回与上一个匹配项匹配的输入子序列。
正则表达式分组 是从左至右计算其左括号有几个就可以分为几组。编号从1开始
第一组 ((A)(B(C)))
第二组 (A)
第三组 (B(C))
第四组 (C)
编号从1 开始 所以 x = 1 x = 2
public static void main(String[] args) {
Pattern p = Pattern.compile("([a-z]+)(\\d+)");
Matcher m = p.matcher("aaa2223bb");
System.out.println(m.find()); // 返回 true 说明该正则匹配aaa2223
System.out.println(m.groupCount()); // 返回2,因为有2组
System.out.println(m.group(1)); // 返回aaa,返回第一组匹配到的子字符串
System.out.println(m.group(2)); // 返回2223,返回第二组匹配到的子字符串
//true
//2
//aaa
//2223
}
在给用户发送消息时通常情况会有相同的消息模板,但其中部分信息跟用户相关,因此需要对消息模板中的变量部分进行替换。而对于一个系统而言可能有很多套完全不同的模板。
public static
Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(msg);
// 1、构建替换占位符实际值的Map
Map
while(matcher.find()) {
MatchResult matchResult = matcher.toMatchResult();
// 第一组匹配到 ${name} ${address}
String placeHolder = matchResult.group();
//第二组匹配到 name address
String key = matchResult.group(1);
Object value = placeHolderMap.get(key);
if(Objects.nonNull(value)) {
mapping.put(placeHolder,value.toString());
}
}
//2、做替换
for(Map.Entry
msg= msg.replace(entry.getKey(), entry.getValue());
}
return msg;
}
public static void main(String[] args) {
String msg = "${name} 项目发生外联,请注意此地址 ${address}";
Map
placeHolderMap.put("name","天河");
placeHolderMap.put("address","192.168.1.12");
String s = replacePlaceHolderWithMapValue(msg, placeHolderMap);
System.out.println(s); //天河 项目发生外联,请注意此地址 192.168.1.12
}
private static Matcher matcher(String str) {
Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(str);
return matcher;
}
实例
public static final String EMAIL_PATTERN = "^[\\w!#$%&'*+/=?`{|}~^-]+(?:\\.[\\w!#$%&'*+/=?`{|}~^-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,6}$";
public static final String CHINESE_PATTERN = "^[\u4e00-\u9fa5]{0,}$";
public static final String CONTAINS_CHINESE_PATTERN = "[\u4E00-\u9FA5|\\!|\\,|\\。|\\(|\\)|\\《|\\》|\\“|\\”|\\?|\\:|\\;|\\【|\\】]";
public static final String NUMBER_ADN_LETTER = "^[A-Za-z0-9]+$";
public static final String NUMBER_ADN_LETTER = "^[A-Za-z0-9]+$";
public static final String QQ_PATTERN = "/[1-9][0-9]{4,}/";
public static final String NUMBER_PATTERN = "[0-9]+";
public static final String LETTER_PATTERN = "[a-zA-Z]+";
public static final String ZIPCODE_PATTERN = "\\p{Digit}{6}";
public static final String PHONE_PATTERN = "^(13[0-9]|14[579]|15[^4,\\D]|16[6]|17[0135678]|18[0-9]|19[89])\\d{8}$";
public static final String TELEPHONE_PATTERN = "^(0\\d{2,3}-)?(\\d{7,8})(-(\\d{3,}))?$";
public static final String TELEPHONE_400_PATTERN = "((400)(\\d{7}))|((400)-(\\d{3})-(\\d{4}))";
public static final String IDCARD_PATTERN = "^((11|12|13|14|15|21|22|23|31"
+ "|32|33|34|35|36|37|41|42|43|44|45|46|50|51|"
+ "52|53|54|61|62|63|64|65|71|81|82|91)\\d{4})"
+ "((((19|20)(([02468][048])|([13579][26]))0229))|"
+ "((20[0-9][0-9])|(19[0-9][0-9]))((((0[1-9])|(1[0-2]))"
+ "((0[1-9])|(1\\d)|(2[0-8])))|((((0[1,3-9])"
+ "|(1[0-2]))(29|30))|(((0[13578])|(1[02]))31))))"
+ "((\\d{3}(x|X))|(\\d{4}))$";
public static final String USERNAME_PATTERN = "^[A-Za-z0-9_]{3,15}$";
public static final String PASSWORD_PATTERN = "^(?![0-9]+$)[0-9A-Za-z]{6,20}$";
public static final String UUID_PATTERN = "[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}";
public static final String YEAR_PATTERN = "^(19|20)\\d{2}$";
public static final String TIME_PATTERN = "^(?:(?:([01]?\\d|2[0-3]):)?([0-5]?\\d):)?([0-5]?\\d)$";
public static final String DATE_PATTERN = "^((\\d{2}(([02468][048])|([13579][26]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))";
public static final String TIME_STAMP_PATTERN = "^((\\d{2}(([02468][048])|([13579][26]))[\\-\\s]?((((0?[13578])|(1[02]))[\\-\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\s]?((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-\\s]?((((0?[13578])|(1[02]))[\\-\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\s]?((0?[1-9])|(1[0-9])|(2[0-8])))))) ([2][0-3]|[0-1][0-9]|[1-9]):[0-5][0-9]:([0-5][0-9]|[6][0])$";
public static final String IPV4_PATTERN = "([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])";
public static final String IPV6_PATTERN = "([0-9a-f]+)\\:([0-9a-f]+)\\:([0-9a-f]+)\\:([0-9a-f]+)\\:([0-9a-f]+)\\:([0-9a-f]+)\\:([0-9a-f]+)\\:([0-9a-f]+)";
public static final String URL_PATTERN = "^(http|https|ftp)\\://([a-zA-Z0-9\\.\\-]+(\\:[a-zA-Z0-9\\.&%\\$\\-]+)*@)?((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|([a-zA-Z0-9\\-]+\\.)*[a-zA-Z0-9\\-]+\\.[a-zA-Z]{2,4})(\\:[0-9]+)?(/[^/][a-zA-Z0-9\\.\\,\\?\\'\\\\/\\+&%\\$#\\=~_\\-@]*)*$";
public static final String DOMAIN_PATTERN = "^(?=^.{3,255}$)[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$";
public static final String INT_OR_FLOAT_PATTERN = "^\\d+\\.\\d+|\\d+$";
public static final String FLOAT_PATTERN = "^(-?\\d+)(\\.\\d+)?$";
public static final String POSITIVE_INTEGER = "[1-9]+\\d{0,10}";
public static final String GIT_URL_PATTERN = "(git@[\\w\\.]+)(:(//)?)([\\w\\.@\\:/\\-~]+)(\\.git)(/)?";
public static final String ARMY_ID_CARD = "南字第(\\d{6,8})号|北字第(\\d{6,8})号|沈字第(\\d{6,8})号|兰字第(\\d{6,8})号|成字第(\\d{6,8})号|济字第(\\d{6,8})号|广字第(\\d{6,8})号|海字第(\\d{6,8})号|空字第(\\d{6,8})号|参字第(\\d{6,8})号|政字第(\\d{6,8})号|后字第(\\d{6,8})号|装字第(\\d{6,8})号";
public static final String[] forbidden = {"\\bselect\\b", "\\bor\\b", "\\bdelete\\b", "\\bjoin\\b", "\\btable\\b"
, "\\bdrop\\b", "\\biframe\\b", "\\bwindow\\b", "\\b_\\b", "\\+", "%", "\\<", "\\>", "'", "=",
"%3C", "\\(", "%28", "alert", "eval((.*))", "script", "location.href"};
//匹配中括号
Pattern pattern = Pattern.compile("\\{\\{(.+?)}}");
推荐阅读
发表评论