正则表达式主要分为两部分:
1.字符:(都是单个字符)
- . : 表示任意单个字符
- \w :表示字母或数字:a-zA-Z0-9, \W则与\w相反, 这样一正一反下来,就表示所有的字符,完全的,一字不漏的。
- \s : 表示空白字符,包括空格,制表符,回车, \S表示与\s相反。
- \d : 表示数字0-9, \D 表示与\d相反。
- [] : 要做更精确地匹配,可以用[]表示范围,
[0-9a-zA-Z\_]
可以匹配一个数字、字母或者下划线;取反,^还能做为取反使用,例如[^abc]表示不包含a,b和c | : A|B
可以匹配A或B,所以(J|j)ava(S|s)cript
可以匹配'JavaScript'
、'Javascript'
、'javaScript'
或者'javascript'
。注意,(J|j)ava(S|s)cript 是加了分组功能的, 什么是分组?
除了简单地判断是否匹配之外,正则表达式还有提取子串的强大功能。用()
表示的就是要提取的分组(Group)。- ^
:
表示行的开头,^\d
表示必须以数字开头,^还能做为取反使用,例如[^abc]表示不包含a,b和c。 $ :
表示行的结束,\d$
表示必须以数字结束。- 特例:如何表示一个特定的字符串?用小括号括起来,(abc)
字符就介绍到这里,基本够用了。
2.字符个数(限定符):
上面介绍了正则表达式常用的字符,但是一个完整的正则表达式必须要包含字符+字符个数,下面介绍常用的表达字符个数的方式:
- ? : 表示0个或1个字符, 例如"\w?" 表示0个或者1个 字母或数字。除了表示个数,?还可以用于阻止贪婪匹配,可以在正则表达式后面加个?,例如\d+贪婪匹配文章中所有数字,\d+?就可以让\d+采用非贪婪匹配,只匹配第一个数字???
- * : 表示任意个字符(包括0个)。
- +: 表示至少一个字符。
- {n}:表示n个字符。
- {n,m}:表示n到m个字符。
Note: 怎样指定某个字符串的个数?用小括号括起来,(abc)*,可以匹配abc,abcabc........
3.总结:
正则表达式其实就是字符+字符个数,掌握这个窍门,只要不是特别复杂的情况下,基本是够用了。
4.非捕获匹配:
有时候会有些变态点儿的需求-- 匹配结果中pattern(正则表达式)部分不出现,这时候就需要非捕获匹配了,匹配的结果中没有pattern部分的内容
4.1案例
我们来看一下这种情况:第三项中(用户名)含有敏感信息,请将其替换为 "xxxxxx"
"success","1","admin","2020-11-10T01:20:30"
"success","2","testuser","2020-11-10T01:21:30"
怎么找到第三项呢? 使用非捕获匹配,也就是说将前三项都写到正则表达式中,但是前两项写为非捕获匹配,最终就能只匹配到第三项
这里给出一个答案:反向肯定预查 (?<=(\"\w*\",\"\w*\",))\"\w*\"
上面案例的代码如下:
没有使用上面的正则表达式(?<=(\"\w*\",\"\w*\",))\"\w*\",而是用{0,10}代替了*,因为:在后行正则表达式中,Java正则引擎不允许没有明确最大长度匹配的可变长度文本。这意味着我们不能在后行模式中使用 * 或 + 限定符。
但在后行正则中,Java正则引擎允许有限制或明确长度的重复行为。通过在后行表达式中使用有限的限定符,这样就能在Java正则表达式中给我们替代的解决方案。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class NoFetchMatchTest {
public static void main(String[] args) {
String content = "\"success\",\"ss\",\"admin\",\"2020-11-10T01:20:30\"";
String regStr = "(?<=\"\\w{0,10}\",\"\\w{0,10}\",)\"\\w*\"";
Pattern pattern = Pattern.compile(regStr);
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
System.out.println(matcher.group()); // "admin"
}
}
}
4.2非捕获匹配详细
下面给出几个常用的非捕获匹配:
Note:能够全部匹配,并且只返回自己需要的那部分字符串
正向:从左往右,正则表达式在右侧
反向:从右向左, 正则表达式在左侧
(?=pattern) | 非捕获匹配 -> 正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串,该匹配不需要捕获供以后使用。 举例说明,“Linux(?=3.0|3.1|3.2|3.3)”能匹配“Linux3.1”中的“Linux”,但不能匹配“Linux4.0”中的“Linux”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 |
(?!pattern) | 非捕获匹配 -> 正向否定预查,在任何不匹配pattern的字符串开始处匹配查找字符串,该匹配同样不需要捕获供以后使用。 举例说明,“Linux(?!3.0|3.1|3.2|3.3)”能匹配“Linux4.0”中的“Linux”,但不能匹配“Linux3.0”中的“Linux”。与正向肯定预查(?=pattern)正好相反 |
(?<=pattern) | 非捕获匹配 -> 反向肯定预查,与正向肯定预查类似,只是方向相反,即放置位置相反,一个在前(反向),一个在后(正向)。 举例说明,“(?<=xp|7|10)Windows”能匹配“10Windows”中的“Windows”,但不能匹配“98Windows”中的“Windows”。 |
(?<!pattern) | 非捕获匹配 -> 反向否定预查,与正向否定预查类似,只是方向相反。例如“(?<!xp|7|10)Windows”能匹配“2000Windows”中的“Windows”,但不能匹配“10Windows”中的“Windows”。 |
(?:pattern) | 捕获匹配(匹配全部字符),匹配包括pattern部分的全部字符,不进行存储(不进行分组,上面几个都会存储分组)供以后使用。这在使用或字符“(|)”来组合一个模式的各个部分时很有用。 举例说明,“industr(?:y|ies)”能够匹配"industries"中的"industr"。“industr(?:y|ies)”是一个比“industry|industries”更简略的表达式。 |
当然可以配合使用, 下面的例子中将网址www.google.com匹配出来
<a target=_blank href="www.google.com">谷歌浏览器</a>
正则表达式:(?<=(href=")).{1,100}(?=(">)), 同时使用了反向肯定预查和正向肯定预查。注意,这里是做了分组的。
5.正则表达式验证网站:
可以在这个网址: 在线正则表达式测试, 去验证自己所写的正则表达式。
在这个网址中,即可以验证自己的正则表达式,又可以测试匹配后的替换功能。例如下面的例子中可以匹配用户名,并且将用户名替换为"xxxxxx"。