大家好,关于深入解析Java中的正则表达式应用技巧很多朋友都还不太明白,今天小编就来为大家分享关于的知识,希望对各位有所帮助!
正则表达式是描述文本模式的一串字符,可以方便地对文本进行处理,包括搜索、替换、切分等。
正则表达式中的字符有两种类型:一种是普通字符,与字符本身匹配;另一种是普通字符。另一种是元字符,它有特殊的含义。元字符及其特殊含义构成了正则表达式的语法。
单个字符
大多数单个字符由字符本身表示,如字符‘0’、‘3’、‘a’、‘马’等,但也有一些单个字符由多个字符表示,这些字符用斜体表示。以栏开头。
特殊字符如制表符“t”、换行符“n”、回车符“r”等。
八进制表示的字符以 开头,后面跟着1到3位数字,如 141,对应的是ASCII编码为97的字符,即字符‘a’。
十六进制表示的字符以x开头,后面跟着两个字符,如x6A,它对应的是ASCII编码为106的字符,即字符‘j’。
Unicode编号表示的字符以u开头,后面跟着4个字符,如u9A6C,代表汉字“马”。它只能表示数字低于0xFFFF的字符。如果超过0xFFFF,则使用x{.}形式,如x{1f48e}。 5
元字符如""、"."、"?"等。为了匹配元字符本身,需要使用转义字符。
字符组
字符组的类型有很多种,包括任意字符、多个指定字符之一、字符范围等。
图片.png
任意字符
"."默认匹配除换行符之外的任何字符。例如:正则表达式a.f 匹配字符串“abf”和“acf”。
您可以指定另一种匹配模式,一般称为单行匹配模式或点匹配模式。在此模式下,“.”匹配任何字符,包括换行符。
有两种方法可以指定匹配模式:
一种是在正则表达式中,以(?s)开头,s代表单行,即单行匹配模式,如:(?s)a.f
一是在程序中指定。在Java中,单行匹配模式对应的模式常量是Pattern.DOTALL。
字符区间
使用方括号[]表示一组,匹配该组中的任意字符。例如:[abcd],匹配a、b、c、d中的任意一个字符;
字符组中可以使用连字符“-”来表示多个连续的字符,如:[0-9]、[a-z];
可以有多个连续的空格等普通字符,如:[0-9a-zA-Z];
"-" 是一个元字符。如果要匹配自身,可以使用转义符,即"-",或者放在字符组的前面。
字符组支持排除的概念。 [ 后跟字符^,例如:[^abcd],匹配除a、b、c、d 之外的任意字符;
^ 是仅位于字符组开头的元字符。如果不在开头,则为普通字符,与自身匹配;
字符组中,除[ ]、、-、^外,字符组外的其他元字符不再具有特殊含义。
有一些以 开头的特殊字符代表一些预定义的字符组:
d: d 表示数字,匹配数字字符,相当于[0-9]。
w: w 代表单词,匹配单词字符,相当于[a-zA-Z_0-9]。
s: s 表示空格,匹配空白字符,相当于[ tnx0Bfr]。
D:匹配非数字字符,即[^d]。
W:匹配非单词字符,即[^w]。
S:匹配非空白字符,即[^s]。
量词
量词是指指定出现次数的元字符。共有三种常见的元字符:+、*、
image.png 表示前面的字符出现一个或多个,例如ab+c,可以匹配abc、abbc 或abbbc。
表示前一个字符出现零次或多次,例如ab*c,可以匹配abc、ac 或abbbc。
?表示前一个字符可能出现也可能不出现,例如ab? c,可以匹配abc 和ac,但不能匹配abbc。
{m,n}更通用的语法是{m,n},出现的次数是从m到n,包括m和n。如果n不受限制,则可以省略。如果m和n相同,则可以写成{m}。
语法必须严格采用{m,n} 形式,逗号周围没有空格。
量词的默认匹配是贪婪的。如果你想在遇到第一个匹配时停止,你应该使用惰性量词并添加一个符号"? " 在量词之后。
分组
表达式可以用方括号()括起来表示一个组,如a(bc)d,bc是一个组,组之间可以嵌套,如a(de(fg))。
默认情况下,组有一个编号,从1 开始,按照括号出现的顺序从左到右递增。 Group 0 是一个特殊的组,其内容是整个匹配的字符串。
a(bc)((de)(fg)) 字符串abcdefg 与该表达式匹配,第1 组是bc,第2 组是defg,第3 组是de,第4 组是fg,第0 组是abcdefg。
该组匹配的子字符串稍后可以像捕获一样访问,因此默认的分组称为捕获组。
括号() 与元字符“|”一起可以指示匹配的子表达式之一,例如:(http|ftp|file)。
您可以使用斜杠 后跟组编号来引用先前匹配的组。这称为反向引用。例如:(w+)(.*)1,1 匹配(w+) 之前的第一组。
使用数字来引用群体时很容易引起混乱。您可以命名该组并按名称引用它。命名组的语法是(?X),引用组的语法是k。
例如:(?w+)(.*)k。
默认组称为捕获组,即捕获该组匹配的内容,以便以后引用。
实现捕获分组是有一定成本的。为了提高性能,如果以后不需要引用该组,可以将其改为非捕获组。语法为(?),如:(?abc|def)。
特殊边界匹配
边界匹配与字符匹配不同。可以认为在字符串中,每个字符的两边都是边界。例如:“一只猫n”。
在正则表达式中,除了指定字符需要满足的条件外,还可以指定字符的边界。表示特殊边界的常用元字符有^、$、A、Z、z 和b。
^ 匹配整个字符串的开头,^abc 表示整个字符串必须以abc 开头。请注意,在字符组内^ 表示排除,但在字符组外它匹配开始。
$ 默认匹配整个字符串的结尾。如果整个字符串以换行符结尾,则匹配换行符之前的边界。例如,表达式abc$表示整个表达式以abc结尾,或者abcrn或abcnEnd。
上面的^和匹配行尾。例如,如果表达式为^abc$,字符串为"abcnabcrn",则将有两个匹配项。
可以通过两种方式指定匹配模式。一种是在正则表达式中,以(?m)开头,m代表多行,即多行匹配模式。另一种是在程序中指定。在Java中,对应的模式常量是Pattern.MULTILINE。
单行模式影响了字符‘.’的匹配规则,使得‘.’可以匹配换行符;多行模式影响^和$的匹配规则,使得行首和行尾能够匹配。两种模式可以一起使用。
起始边界A 与^ 类似。无论采用哪种模式,整个字符串的起始边界始终是匹配的。
结束边界Z 和z 与$ 相同,匹配换行符之前的边界,而z 始终匹配结束边界。
单词边界b 匹配单词边界,如bcatb 匹配完整的单词c at ,不能匹配类别。 b 并不匹配特定字符,而是匹配满足要求的边界:一侧是单词字符,另一侧不是单词字符。在Java中,除了w之外,b识别的单词字符还包括汉字。
image.png
环视边界匹配
Lookaround 匹配边界,表达式是边界左侧或右侧字符串的要求。对于同一个边界,可以指定多个需求,即编写多个lookarounds。
正序查找语法为(?=.),要求右边的字符串与指定的表达式匹配。例如,表达式abc(?=def),(?=def)在字符c的右侧,即匹配c右侧的边界。这个边界的要求是:它的右边有def,比如abcdef。如果不是,则不匹配,如abcd。
负序查找的语法为(?),要求右侧的字符串不能匹配指定的表达式。例如,表达式s(? ing) 匹配普通s,但不匹配s 后跟ing。注意:避免与独占字符组混淆,例如s[^ing],它匹配两个字符,第一个是s,第二个是除了i、n、g 之外的任意字符。
正反向查找的语法是(?=.),要求左边的字符串与指定的表达式匹配。例如,如果表达式(?=s)abc, (?=s) 位于字符a 的左侧,则它与a 的左边界匹配。这个边界的要求是左边必须有空白字符。
负向反向环视的语法是(?
环视结构也称为断言。断言的对象是边界。边界不占用字符且没有宽度,因此也称为零宽度断言。
顺序环顾也可以出现在左侧,反向环顾也可以出现在右侧。
例如:(?=.*[A-Z])w+,w+匹配多个单词字符,(?=.*[A-Z])匹配单词字符的左边界,这是肯定顺序环顾四周,左边border of 的要求是其右侧的字符串与表达式.*[A-Z]匹配,即其右侧必须至少有一个大写字母。
匹配模式
image.png 在正则表达式中,可以指定多个模式。
单线匹配模式也称为点匹配模式。在此模式下,“.”匹配任何字符,包括换行符。有两种方法可以指定匹配模式:
一种是在正则表达式中,以(?s)开头,s代表单行,即单行匹配模式,如:(?s)a.f;
一是在程序中指定。 Java中对应的模式常量是Pattern.DOTALL。
多行匹配模式在该模式下,将以行为单位进行匹配。 ^ 匹配行首,$ 匹配行尾。例如,表达式为^abc$ ,字符串为"abcnabcrn" ,将有两个匹配项。
有两种方法可以指定匹配模式:
一种是在正则表达式中,以(?m)开头,m代表multi-line,即多行匹配模式;
一是在程序中指定。 Java中对应的模式常量是Pattern.MULTILINE。
一种不区分大小写的模式是在正则表达式的开头使用(? i),i 被忽略,例如: (? i)the;
程序中指定一种,Java中对应的模式常量为Pattern.CASE_INSENSITIVE。
Java API
正则表达式相关类位于java.util.regex 包下。主要有两个类,一是Pattern,二是Matcher。
Pattern
Pattern 表示独立于正在处理的特定字符串的正则表达式对象。
表示正则表达式正则表达式由元字符和普通字符组成。在正则表达式中,字符“”是元字符。为了表示""本身,需要对其进行转义,即"\"。
在Java中,需要使用字符串来表示正则表达式,而在字符串中,""也是一个元字符。要表示""本身,需要用它来转义,即"\"。
为了在字符串中表示正则表达式“”本身,使用了四个“”。正则表达式的字符串表示形式可以编译为Pattern 对象。
字符串正则表达式="(\w+)(.*)\1";
模式模式=Pattern.compile(regex);编译有一定的成本。 Pattern对象只与正则表达式有关,与具体要处理的文本无关。它可以被多个线程安全地共享。您应该尝试重用Pattern对象以避免重复编译。
Pattern的compile方法接受一个额外的参数,该参数可以指定匹配的模式。多个模式可以一起使用并通过“|”连接。
Pattern.DOTALL 单线图案(圆点图案)
Pattern.MULTILINE多线图案
Pattern.CASE_INSENSI-TIVE 大小写无关模式
Pattern.LITERAL正则表达式的元字符将失去其特殊含义,被视为普通字符,与Pattern的静态quote()方法效果相同。
如果分隔符包含元字符,例如,分割String 的split 会将regex 参数视为正则表达式而不是普通字符串。 $ | ( ) [ { ^ ? * + ,你需要转义。
如果分隔符是用户指定的并且程序事先不知道,则可以通过Pattern.quote() 将其视为普通字符串。
分隔符不必是字符。例如,可以使用一个或多个空白字符或句点作为分隔符。
String str=" abc def hello.n world";
String[] fields=str.split("[\s.]+");
System.out.println(Arrays.toString(fields));需要注意的是,返回的结果数组中不会包含尾部空白字符串,但会包含头部和中间空白字符串。
字符串str=", abc, def, ";
String[] fields=str.split(", ");
System.out.println("字段num:"+fields.length); //字段num: 4
System.out.println(Arrays.toString(fields)); //[, abc, def] 如果字符串中没有找到匹配正则表达式的分隔符,则返回数组长度为1,元素为原始字符串。
Pattern还有一个split方法,与String方法的定义类似:
public String[] split(CharSequence input)1) Pattern接受的参数是CharSequence,比较通用。 String、StringBuilder、StringBuffer、CharBuffer等都实现了这个接口。
2)如果正则表达式的长度大于1或者包含元字符,则String的split方法必须先将正则表达式编译成Pattern对象,然后调用Pattern的split方法。为了避免重复编译,应该首先使用Pattern方法。
3)如果regex是字符而不是元字符,String的split方法将采用更简单、更高效的实现。在这种情况下,应该首先使用String的split方法。
验证检查输入文本是否完全匹配预定义的正则表达式,通常用于检查用户的输入是否合法。
字符串匹配:
公共布尔匹配(字符串正则表达式){
返回Pattern.matches(正则表达式, this);
}实际上所谓的是Pattern的匹配:
公共静态布尔匹配(字符串正则表达式,CharSequence 输入){
模式p=Pattern.compile(regex);
匹配器m=p.matcher(input);
返回m.matches();
}
Matcher
Matcher 表示将正则表达式应用于特定字符串的匹配,通过它对字符串进行处理。
查找public static void find(){
字符串正则表达式="\d{4}-\d{2}-\d{2}";
模式模式=Pattern.compile(regex);
String str="今天是2017-06-02,昨天是2017-06-01";
匹配器matcher=pattern.matcher(str);
while(matcher.find()){
System.out.println("查找" + matcher.group()
+"position:"+matcher.start()+"-"+matcher.end());
}
}Matcher的内部记录有一个位置,从0开始。find方法从这个位置开始查找与正则表达式匹配的子串。找到后返回true并更新内部位置。
可以通过以下方法获取匹配的子串信息:
//完整的子串匹配,group()实际上调用了group(0),意思是获取第0个匹配的组的内容。 Group 0 是一个特殊的组,表示整个匹配的子串。
公共字符串组()
//子串的起始位置
公共int 开始()
//在子串末尾加1
公共int结束()
//组号group的内容
公共字符串组(int组)
//组号为组的起始位置
公共int 开始(int 组)
//组号为组结束位置加1
公共int结束(int组)
//group(0) 不算
公共int groupCount()
//将名为name的内容分组
公共字符串组(字符串名称)公共静态无效findGroup(){
字符串正则表达式="(\d{4})-(\d{2})-(\d{2})";
模式模式=Pattern.compile(regex);
String str="今天是2017-06-02,昨天是2017-06-01";
匹配器matcher=pattern.matcher(str);
while (matcher.find()) {
System.out.println("year:" + matcher.group(1)
+ ", 月:" + matcher.group(2) + ", 日:" + matcher.group(3));
}
}替换String的ReplaceAll和replaceFirst实际上调用了Pattern和Matcher中的方法。
公共字符串replaceAll(字符串正则表达式,字符串替换){
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}为了避免元字符的干扰,可以使用Matcher的quoteReplacement静态方法将其视为普通字符串。
public static String quoteReplacement(String s) 除了一次性替换操作之外,Matcher 还定义了搜索和替换的方法。
公共匹配器appendReplacement(StringBuffer sb,字符串替换)
public StringBufferappendTail(StringBuffersb)Patternpattern=Pattern.compile("cat");
Matcher matcher=pattern.matcher("一只猫,两只猫,三只猫");
StringBuffer sb=new StringBuffer(); //sb存储最终的替换结果
int 发现数=0;
while(matcher.find()){
matcher.appendReplacement(sb,"狗");
发现数++;
if(foundNum==2) 中断;
}
matcher.appendTail(sb);
System.out.println(sb.toString());除了搜索位置之外,Matcher 还有一个追加位置,最初为0。当找到匹配的子字符串时,appendReplacement() 会做三件事:
1) 将追加位置追加到当前匹配之前的子字符串到sb中。在第一次操作中,它是“一”,在第二次操作中,它是“,二”(注意空格)。
2) 将替换字符串附加到sb。
3) 将追加位置更新为当前匹配之后的位置。
appendTail 将追加位置之后的所有字符追加到sb 中。
模板引擎
模板是一个字符串,中间有一些变量,用{name}表示。
String template="Hi {name}, your code is {code}.";上面的模板字符串中有两个变量:一个是name,另一个是code。
变量的实际值是通过Map提供的,变量名对应Map中的key。模板引擎的任务是接受模板和Map作为参数,并返回替换变量后的字符串。
公共类模式模板{
私有静态模式templatePattern=Pattern.compile("\{(\w+)\}");
公共静态字符串模板引擎(字符串模板,Mapparams){
StringBuffer sb=new StringBuffer();
//查找所有模板变量,正则表达式为{(w+)}
匹配器matcher=templatePattern.matcher(template);
while(matcher.find()){
字符串键=matcher.group(1);
对象值=params.get(
key); matcher.appendReplacement(sb,value != null ? Matcher.quoteReplacement(value.toString()) : ""); } matcher.appendTail(sb); return sb.toString(); } public static void main(String[] args) { String template = "Hi {name},your code is {code}"; Mapparams = new HashMap<>(); params.put("name","JOJO"); params.put("code","6789"); System.out.println(templateEngine(template, params)); }【深入解析Java中的正则表达式应用技巧】相关文章:
2.米颠拜石
3.王羲之临池学书
8.郑板桥轶事十则
用户评论
我一直觉得正则表达式好强大,可惜我学不会啊
有16位网友表示赞同!
之前遇到个很麻烦的数据处理问题,幸好找到了Java正则表达式的解决方案
有12位网友表示赞同!
最近在学习Java开发,正则表达式这一块感觉有点搞不懂
有8位网友表示赞同!
想问一下,用Java正则表达式怎么匹配中英文混合的字符串?
有13位网友表示赞同!
有没有推荐资料或者教程可以帮助我入门Java正则表达式?
有15位网友表示赞同!
学习Java正好碰到正则表达式的学习,感觉很有潜力
有12位网友表示赞同!
Java正则表达式真是个宝藏工具,很多场景都可以用得着
有10位网友表示赞同!
平时工作中经常用到Java正则表达式,真得超级好用
有6位网友表示赞同!
觉得Java的正则表达式语法有点复杂,需要好好琢磨琢磨
有13位网友表示赞同!
学习了Java正则表达式后,感觉数据处理效率大大提升了
有6位网友表示赞同!
对于初学者来说,Java正则表达式的学习曲线还是比较陡峭
有20位网友表示赞同!
想做一些文本分析,Java正则表达式看起来非常强大
有14位网友表示赞同!
有没有人分享下Java正则表达式经典示例?太难懂了
有10位网友表示赞同!
感觉Java正则表达式可以解决很多日常开发中的问题
有20位网友表示赞同!
学习新的编程语言总是要学习其工具和知识,正则表达式也是其中之一
有8位网友表示赞同!
在软件开发过程中,掌握Java正则表达式是一项必备技能
有12位网友表示赞同!
虽然Java正则表达式看起来复杂,但它的应用场景很多
有20位网友表示赞同!
用Java正则表达式可以更方便地对文本进行过滤和处理
有14位网友表示赞同!
我对Java的开发生态非常感兴趣,包括正则表达式的学习
有7位网友表示赞同!