正则表达式实例笔记 (java.util.regex)
正则表达式就是一个描述规则的字符串。
参考资料:https://www.liaoxuefeng.com/wiki/1252599548343744/1304066130968610
一 使用
正常的正则表达式为
"20\d\d"
,其中"\d"
表示任意一个数字且前两位固定为20;但在java语言中需要用"\\"
表示"\"
,故java中写作"20\\d\\d"
。
//java中使用正则
public static void main(String[] args) {
String regex = "20\\d\\d";
System.out.println("2019".matches(regex)); // true
System.out.println("2100".matches(regex)); // false
}
//对应源码 String.java
public boolean matches(String regex) {
return Pattern.matches(regex, this);
}
1 . 常用匹配规则
import org.junit.*;
/**
* @author r
* @description 测试正则
* @date 2020/11/25
*/
public class TestRegex {
@Test
public void testNum() {
// \d 匹配 数字 (仅限一个)
String phoneRule = "1\\d{10}"; //手机号码验证
Assert.assertFalse("13122224444".matches("\\d"));
Assert.assertTrue("13122224444".matches(phoneRule));
Assert.assertFalse("1312222".matches(phoneRule));
Assert.assertFalse("23122224444".matches(phoneRule));
Assert.assertFalse("1312222444x".matches(phoneRule));
// \D 匹配 非数字
String rule = "1\\D{4}";
Assert.assertTrue("1aA?你".matches(rule));
Assert.assertFalse("1aA?你x".matches(rule));
Assert.assertFalse("1aA?2".matches(rule));
Assert.assertFalse("12".matches(rule));
}
@Test
public void testChar() {
// \w 匹配一个常用字符,包括字母、数字、下划线
String charRule = "1\\w{1,4}";
Assert.assertTrue("1a".matches(charRule));
Assert.assertTrue("1aB".matches(charRule));
Assert.assertFalse("1aB!".matches(charRule));
Assert.assertTrue("1aB2".matches(charRule));
Assert.assertFalse("1aB你".matches(charRule));
// \W 非
String rule = "1\\W{1,4}";
Assert.assertFalse("1a".matches(rule));
Assert.assertFalse("1aB".matches(rule));
Assert.assertTrue("1!".matches(rule));
Assert.assertFalse("1aB2".matches(rule));
Assert.assertTrue("1你".matches(rule));
}
@Test
public void testOper() {
// . 匹配 任意字符(仅限一个)
String rule = "1.x";
Assert.assertTrue("13x".matches(rule));
Assert.assertTrue("1xx".matches(rule));
Assert.assertTrue("1?x".matches(rule));
Assert.assertTrue("1你x".matches(rule));
Assert.assertFalse("1312222444x".matches(rule));
// \s 匹配空格和TAB
String rule1 = "1\\sx";
// * 可以匹配任意次,包括 0 次, 等价于 {0,}
Assert.assertTrue("".matches("\\d*"));
Assert.assertTrue("1".matches("\\d*"));
Assert.assertTrue("13".matches("\\d*"));
// + 表示 至少匹配一次,包括 0 次, 等价于 {1,}
Assert.assertFalse("".matches("\\d+"));
Assert.assertTrue("1".matches("\\d+"));
Assert.assertTrue("13".matches("\\d+"));
// ? 表示 要么匹配 0 次,要么匹配 1 次, 等价于 {0,1}
Assert.assertTrue("".matches("\\d?"));
Assert.assertTrue("1".matches("\\d?"));
Assert.assertFalse("13".matches("\\d?"));
// ^ 匹配开头 ; $ 匹配结尾
Assert.assertFalse("".matches("^xxx"));
Assert.assertFalse("x".matches("^xxx"));
Assert.assertTrue("xxx".matches("^xxx"));
Assert.assertTrue("xxxxx".matches("^xxx*$"));
}
@Test
public void testOther() {
// [] 匹配指定范围内
String rule1 = "[1-2][a-b|A]";
Assert.assertFalse("1".matches(rule1));
Assert.assertFalse("1aa".matches(rule1));
Assert.assertTrue("1a".matches(rule1));
Assert.assertFalse("1z".matches(rule1));
Assert.assertTrue("1A".matches(rule1));
// [^ ] 匹配指定范围外
String rule2 = "[^1-2][a-b|A]";
Assert.assertFalse("1a".matches(rule2));
Assert.assertTrue("0a".matches(rule2));
}
}
2 . 提取匹配字段
import org.junit.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author r
* @description 测试正则提取数据
* @date 2020/11/25
*/
public class TestRegex {
@Test
public void test() {
//提取地址
String address = "北京市-昌平区+西二旗:xx大厦";
String x = address.substring(0,address.indexOf("-"));
Assert.assertTrue("北京市".matches(x));
}
@Test
public void test1() {
//提取地址 使用括号可将正则括起来,并表示为一个变量
String address = "北京市-昌平区+西二旗:xx大厦";
Pattern pattern = Pattern.compile("(.+)[-+:](.+)[-+:](.+)[-+:](.+)");
Matcher matcher = pattern.matcher(address);
boolean res = matcher.matches();
Assert.assertTrue(res);
Assert.assertTrue("北京市".matches(matcher.group(1)));
Assert.assertTrue("昌平区".matches(matcher.group(2)));
Assert.assertTrue("西二旗".matches(matcher.group(3)));
Assert.assertTrue("xx大厦".matches(matcher.group(4)));
}
@Test
public void test2() {
//提取地址
String address = "北京市-昌平区+西二旗:xx大厦";
Assert.assertTrue("北京市".matches(address.split("[-+:]")[0]));
Assert.assertTrue("昌平区".matches(address.split("[-+:]")[1]));
Assert.assertTrue("西二旗".matches(address.split("[-+:]")[2]));
Assert.assertTrue("xx大厦".matches(address.split("[-+:]")[3]));
}
@Test
public void test3() {
//替换地址中所有的分隔符为 “-”
String address = "北京市-昌平区+西二旗:xx大厦";
String newAddress = "北京市-昌平区-西二旗-xx大厦";
String tmpAddress = address.replaceAll("[-+:]","-");
Assert.assertTrue(newAddress.equals(tmpAddress));
//替换地址中所有的分隔符为 “aa”+ 分隔符 + “+”,可使用 $1 $2 ...等表示分隔符,并且需要将正则用“()”括起来
String newAddress1 = "北京市aa-aa昌平区aa+aa西二旗aa:aaxx大厦";
String tmpAddress1 = address.replaceAll("([-+:])","aa$1aa");
Assert.assertTrue(newAddress1.equals(tmpAddress1));
}
@Test
public void test4() {
String tStr = "wwwssss";
//贪婪匹配 正则表达式会默认的将前面匹配规则尽可能向后延伸
Pattern pattern = Pattern.compile("(\\w+)(s*)");
Matcher matcher = pattern.matcher(tStr);
Assert.assertTrue(matcher.matches());
Assert.assertTrue("wwwssss".matches(matcher.group(1)));
Assert.assertTrue("".matches(matcher.group(2)));
//非贪婪匹配 在前一个匹配规则后加一个 “?”即可
Pattern pattern1 = Pattern.compile("(\\w+?)(s*)");
Matcher matcher1 = pattern1.matcher(tStr);
Assert.assertTrue(matcher1.matches());
Assert.assertTrue("www".matches(matcher1.group(1)));
Assert.assertTrue("ssss".matches(matcher1.group(2)));
}
@Test
public void test5() {
//字符串搜索
String tStr = "s abcxabcdadabc";
Pattern p = Pattern.compile("\\wb\\w");
Matcher matcher = p.matcher(tStr);
while(matcher.find()){
Assert.assertTrue("abc".matches(tStr.substring(matcher.start(),matcher.end())));
}
}
}
结论:
-
1.通过以上test()和test1()两种方式对比,test1() 的方式在复杂字符串匹配上更有优势,且通过此笔记最开头的源码中可以看出,String.matches()方法的本质也是在使用Pattern类实现,如果我们在大量匹配同一正则表达式时,直接采用test1()方式更能减少对象的创建,提高效率;
-
2.通过以上test2()、test3()两种方式可知,有很多的String方法是可以通过传递正则来更加灵活的完成目标;
-
3.通过test4()方法可知正则默认使用贪婪匹配,使用时需要注意;
-
4.test5()为正则的其它应用。
3 . 可能用到的
参考资料:https://blog.csdn.net/longting_/article/details/80328361 。
#一、 4到16位(字母,数字,下划线,减号)
if re.match(r'^[a-zA-Z0-9_-]{4,16}$', "abwc"):
print("匹配1")
######################################################
#二、 密码强度正则,最少6位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符
if re.match(r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*[0-9])(?=.*[!@#$%^&*()-]).{6,}$','Ad2-@jb'):
print('匹配2')
######################################################
# 三、整数正则,分正负
# 正整数原则
if re.match(r'^\d+$','23'):
print('匹配3-正整数')
# 负整数原则
if re.match(r'^-\d+$', '-23'):
print('匹配3-负整数')
# 整数原则
if re.match(r'^-?\d+$', '23'):
print('匹配3-整数')
######################################################
# 四、小数正则,分正负
# 正小数原则
if re.match(r'^\d+\.\d+$','23.67'):
print('匹配4-正小数')
# 负小数原则
if re.match(r'^-\d+\.\d+$', '-23.78'):
print('匹配4-负小数')
# 小数原则
if re.match(r'^-?\d+\.\d+$', '23.89'):
print('匹配4-小数')
#####################################################
# 五、邮箱
if re.match(r'^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$', "153522217@qq.com"):
print("匹配5")
######################################################
# 六、手机号
if re.match(r'^(13[0-9])|(14[57])|(15[0-35-9])|(17[78])|(18[0-9])\d{8}$','14578789090'):
print('匹配6')
##########################################################
# 七、身份证号(18位)正则 345667-19901212-3456
if re.match(r'^[1-9]\d{5}(18|19|[23]\d)\d{2}[0-1][0-9][0-3][0-9]\d{3}[0-9Xx]$','12345619900909889x'):
print('匹配7')
##########################################################
# 八、车牌号正则
if re.match(r'^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$',"京K39006"):
print("匹配8")
##########################################################
# 九、匹配中文
if re.match(r'[\u4E00-\u9FA5]+',"中"):
print("匹配9")