如果需要匹配的字符串含有特殊字符,那就需要用 \转义。比如 a&b,在用正则表达式匹配时,需要使用 a\&b,又由于在 Java 字符串中,\ 也是特殊字符,它也需要转义,所以 a\&b 对应的 Java 字符串是 a\\&b,它是用来匹配 a&b 的。
System.out.println("a&b".matches("a\\&b")); // 输出为 true
\d\d 就能匹配两个数字,\d\d\d 能匹配三个数字,需要匹配几个数字就写几次就行了。
System.out.println("1".matches("\\d\\d")); // 输出为 false System.out.println("11".matches("\\d\\d")); // 输出为 true System.out.println("111".matches("\\d\\d")); // 输出为 false
在 \d 后面打上花括号 {},{n} 表示匹配 n 次。\d{10000} 就表示匹配 10000 个数字。如果要匹配 n ~ m 次,用 {n,m} 即可,如果要匹配至少 n 次,用 {n,} 即可。需要注意 , 后不能有空格。
System.out.println("1".matches("\\d{1,2}")); // 输出为 true System.out.println("12".matches("\\d{1,2}")); // 输出为 true System.out.println("123".matches("\\d{1,2}")); // 输出为 false System.out.println("123".matches("\\d{2,}")); // 输出为 true
正则的基础规则中,除了 \d,还有 \w和\s,w 是 word 的简写,表示匹配一个常用字符,包括字母、数字、下划线。s 是 space 的简写,表示匹配一个空格,包括三种:空格键打出来的空格/Tab 键打出来的空格/回车键打出来的空格。
System.out.println("LeetCode_666".matches("\\w{12}")); // 输出为 true System.out.println("\t \n".matches("\\s{3}")); // 输出为 true System.out.println("Leet\tCode 666".matches("\\w{4}\\s\\w{4}\\s\\d{3}")); // 输出为 true
将字母换成大写,就表示相反的意思。用 \d 你可以匹配一个数字,\D 则表示匹配一个非数字。类似地,\W 可以匹配 \w 不能匹配的字符,\S 可以匹配 \s 不能匹配的字符。
System.out.println("a".matches("\\d")); // 输出为 false System.out.println("1".matches("\\d")); // 输出为 true System.out.println("a".matches("\\D")); // 输出为 true System.out.println("1".matches("\\D")); // 输出为 false
我们对某些位置的字符没有要求,仅需要占个位置即可。这时候我们就可以用 . 字符。我们对匹配的次数没有要求,匹配任意次均可,这时,我们就可以用 * 字符。出现了 0 次,* 是指 可以匹配任意次,包括 0 次。也就是说,* 等价于 {0,}
System.out.println("1".matches("\\d*")); // 输出为 true System.out.println("123".matches("\\d*")); // 输出为 true System.out.println("".matches("\\d*")); // 输出为 true
可以用 + 匹配,+ 表示 至少匹配一次。它等价于 {1,}
System.out.println("1".matches("\\d+")); // 输出为 true System.out.println("123".matches("\\d+")); // 输出为 true System.out.println("".matches("\\d+")); // 输出为 false
如果某个字符要么匹配 0 次,要么匹配 1 次,我们就可以用 ? 匹配。它等价于 {0,1}
如果我们规定电话号码不能以 0 开头,正则匹配规则是 [123456789]\d{10}。
System.out.println("1".matches("[1-9a-gU-Z]")); // 输出为 true System.out.println("b".matches("[1-9a-gU-Z]")); // 输出为 true System.out.println("X".matches("[1-9a-gU-Z]")); // 输出为 true System.out.println("A".matches("[1-9a-gU-Z]")); // 输出为 false
考虑一个实际需求,有许许多多以下格式的字符串,你需要用正则表达式匹配出其姓名和年龄。
Name:Aurora Age:18
其中还夹杂着一些无关紧要的数据
Name:Bob Age:20
错误的数据有着各种各样错误的格式
Name:Cassin Age:22
观察字符串的规则,只需要用 Name:\w+\s*Age:\d{1,3} 就能匹配了。
System.out.println("Name:Aurora Age:18".matches("Name:\\w+\\s*Age:\\d{1,3}")); // 输出为 true System.out.println("其中还夹杂着一些无关紧要的数据".matches("Name:\\w+\\s*Age:\\d{1,3}")); // 输出为 false System.out.println("Name:Bob Age:20".matches("Name:\\w+\\s*Age:\\d{1,3}")); // 输出为 true System.out.println("错误的数据有着各种各样错误的格式".matches("Name:\\w+\\s*Age:\\d{1,3}")); // 输出为 false System.out.println("Name:Cassin Age:22".matches("Name:\\w+\\s*Age:\\d{1,3}")); // 输出为 true Pattern pattern = Pattern.compile("Name:(\\w+)\\s*Age:(\\d{1,3})"); Matcher matcher = pattern.matcher("Name:Aurora Age:18"); if(matcher.matches()) { String group1 = matcher.group(1); String group2 = matcher.group(2); System.out.println(group1); // 输出为 Aurora System.out.println(group2); // 输出为 18 }
只要用 () 将需要取值的地方括起来,传给 Pattern 对象,再用 Pattern 对象匹配后获得的 Matcher 对象来取值就行了。每个匹配的值将会按照顺序保存在 Matcher 对象的 group 中。用 () 把 \\w+ 和 \\d{1,3} 分别括起来了,判断 Pattern 对象与字符串是否匹配的方法是 Matcher.matches(),如果匹配成功,这个函数将返回 true,如果匹配失败,则返回 false。
group(0) 被用来保存整个匹配的字符串了。
考虑一个实际场景:你有一个让用户输入标签的输入框,用户可以输入多个标签。可是你并没有提示用户,标签之前用什么间隔符号隔开。
二分,回溯,递归,分治
搜索;查找;旋转;遍历
数论 图论 逻辑 概率
System.out.println(Arrays.toString("二分,回溯,递归,分治".split("[,;\\s]+"))); System.out.println(Arrays.toString("搜索;查找;旋转;遍历".split("[,;\\s]+"))); System.out.println(Arrays.toString("数论 图论 逻辑 概率".split("[,;\\s]+"))); System.out.println("二分,回溯,递归,分治".replaceAll("[,;\\s]+", ";")); System.out.println("搜索;查找;旋转;遍历".replaceAll("[,;\\s]+", ";")); System.out.println("数论 图论 逻辑 概率".replaceAll("[,;\\s]+", ";"));
在 replaceAll 的第二个参数中,我们可以通过 $1,$2,…来反向引用匹配到的子串。只要将需要引用的部分用 () 括起来就可以了。
System.out.println("二分,回溯,递归,分治".replaceAll("([,;\\s]+)", "---$1---")); System.out.println("搜索;查找;旋转;遍历".replaceAll("([,;\\s]+)", "---$1---")); System.out.println("数论 图论 逻辑 概率".replaceAll("([,;\\s]+)", "---$1---"));
输出为:
二分---,---回溯---,---递归---,---分治 搜索---;---查找---;---旋转---;---遍历 数论--- ---图论--- ---逻辑--- ---概率
贪婪匹配和贪心算法原理是一致的。与之对应的匹配方式叫做 非贪婪匹配,非贪婪匹配 会在能匹配目标字符串的前提下,尽可能少的向后匹配。
在需要非贪婪匹配的正则表达式后面加个 ? 即可表示非贪婪匹配。
Pattern pattern = Pattern.compile("(\\w+?)(e*)"); Matcher matcher = pattern.matcher("LeetCode"); if (matcher.matches()) { String group1 = matcher.group(1); String group2 = matcher.group(2); System.out.println("group1 = " + group1 + ", length = " + group1.length()); System.out.println("group2 = " + group2 + ", length = " + group2.length()); }
str.replaceAll(“[\\.。]+”, “”) 可以匹配所有的. 和 。
消除str.replaceAll(“[^0-9a-zA-Z]”, “”)消除所有的非大小写字母和数字的非法字符。