Java正则表达式

时间:2022-07-28
本文章向大家介绍Java正则表达式,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

[TOC]

0x00 快速入门

目录一览
  • 正则表达式的概述和简单使用
  • 正则表达式的分类及演示
  • 正则表达式的分割功能及案例
  • 正则表达式的替换功能
  • 正则表达式的分组功能
  • Pattern和Matcher的概述
  • 正则表达式的获取功能
概述和正则元字符

描述:正则表达式 是指一个用来描述或者匹配一系列符合某个语法规则的字符串的单个字符串。其实就是一种规则。有自己特殊的应用。

  • 作用:比如注册邮箱,邮箱有用户名和密码,一般会对其限制长度,这个限制长度的事情就是正则表达式做的

正则元字符: 0:特殊字符

x 字符x
\ 转义
n The character with octal value 0n (0 <= n <= 7) 
nn The character with octal value 0nn (0 <= n <= 7) 
mnn The character with octal value 0mnn (0 <= m <= 3, 0 <= n <= 7) 
xhh 十六进制表示 value 0xhh 
uhhhh The character with hexadecimal value 0xhhhh 
x {h...h}十六进制值0xh…h的字符(Character.MIN_CODE_POINT  <= 0xh...h <=  Character.MAX_CODE_POINT) 
t tab键字符 ('u0009') 
n 换行字符 ('u000A') 
r 回车字符 ('u000D') 
f 换页符('u000C') 
a 警铃字符 ('u0007') 
e 转义字符 ('u001B') 
cx 与x对应的控制字符,如cM (Ctrl+M)

#Linebreak匹配器
R 任何Unicode换行序列,都相当于u000Du000A|[u000Au000Bu000Cu000Du0085u2028u2029]

A:字符类

#字符类运算符的优先级如下,从最高到最低:
1.Literal escape     	x
2.Grouping 	[...]
3.Range 	a-z
4.Union 	[a-e][i-u]
5.Intersection 	[a-z&&[aeiou]]

#字符类一览表
* [abc] | [0-9]  #a、b 或 c(简单类)或者0到9的字符都包括
* [^abc]  #任何字符,除了 a、b 或 c(否定) 
* [a-zA-Z] #a到 z 或 A到 Z,两头的字母包括在内(范围) 
* [a-d[m-p]]    #并集 [a-dm-p] (union) 
* [a-z&&[def]] #交集
* [a-z&&[^bc]] #补集 [a-z&&[^m-p]];

B:预定义字符类

* . 任何字符。
* d 数字:[0-9]
* D 非数字: [^0-9]
* w 单词字符:[a-zA-Z_0-9]
* W 非单词字符:[^w]
* h 水平空白字符: [txA0u1680u180eu2000-u200au202fu205fu3000] 
* H 非水平空白字符:: [^h] 
* v 垂直空格字符:: [nx0Bfrx85u2028u2029]  
* V 非垂直空格字符:: [^v] 
* s 空格字符: [ tnx0Bfr] 
* S 非空格字符: [^s]

C:Greedy 数量词

#贪婪量词
* X? 一次或一次也没有
* X* 零次或多次
* X+ 一次或多次
* X{n} X恰好 n 次 
* X{n,} X至少 n 次 
* X{n,m} X至少 n 次


#非贪婪量词
X?? X, once or not at all 
X*? X, zero or more times 
X+? X, one or more times 
X{n}? X,匹配n次或者0次
X{n,}? X,至少n次
X{n,m}? X,至少n次,但不超过m次


#占有欲强的量词
X?+ X, once or not at all 
X*+ X, zero or more times 
X++ X, one or more times 
X{n}+ X, exactly n times 
X{n,}+ X, at least n times 
X{n,m}+ X, at least n but not more than m times

D:定界匹配符号(Boundary matchers )

^ 行开头
$ 行结尾
b 单词边界
B 非单词边界
A 输入的开始 (NEW)
G 上次匹配结束 (NEW)
Z 输入结束符但对于最终终止符,如果有的话  (NEW)
z 输入结束 (NEW)

#Quotation 
 Nothing, but quotes the following character 
Q 只是以E结尾的引用结束
E 只是以Q开头的引用结束

E:逻辑操作符(logical Operators)

XY  X后面跟着Y
X|Y X或者Y
(X) X捕获组

F:元组与捕获组

#特殊的结构 Special constructs (named-capturing and non-capturing) 
(X)       #常规元组捕获
(?<name>X) #X,名称元组捕获named-capturing group 
(?:X) X, as a non-capturing group  #非补货组
(?idmsuxU-idmsuxU)  Nothing, but turns match flags i d m s u x U on - off 
(?idmsux-idmsux:X)   X, as a non-capturing group with the given flags i d m s u x on - off 

(?=X) X, via zero-width positive lookahead  #肯定型顺序环视 (从左到右) 当前位置的右边
(?!X) X, via zero-width negative lookahead  #否定型顺序环视

(?<=X) X, via zero-width positive lookbehind  #肯定型逆序环视 (从右到左) 当前位置的左边
(?<!X) X, via zero-width negative lookbehind  #否定型逆序环视

(?>X) X, as an independent, non-capturing group 


#Back references(向后引用)
n 无论第n个捕获组匹配什么,如([a-z]) 可以采用1调用元组捕获的值;
k<name> 无论名称捕获组“name”匹配什么;

G:其他扩展元字符字符POSIX字符类

#POSIX character classes (US-ASCII only) 
p{Lower} A lower-case alphabetic character: [a-z] 
p{Upper} An upper-case alphabetic character:[A-Z] 
p{ASCII} All ASCII:[x00-x7F] 
p{Alpha} An alphabetic character:[p{Lower}p{Upper}] 
p{Digit} A decimal digit: [0-9] 
p{Alnum} An alphanumeric character:[p{Alpha}p{Digit}] 
p{Punct} Punctuation: One of !"#$%&'()*+,-./:;<=>[email protected][]^_`{|}~ 
p{Graph} A visible character: [p{Alnum}p{Punct}] 
p{Print} A printable character: [p{Graph}x20] 
p{Blank} A space or a tab: [ t] 
p{Cntrl} A control character: [x00-x1Fx7F] 
p{XDigit} A hexadecimal digit: [0-9a-fA-F] 
p{Space} A whitespace character: [ tnx0Bfr] 
  
#java.lang.Character classes (simple java character type) 
p{javaLowerCase} Equivalent to java.lang.Character.isLowerCase() 
p{javaUpperCase} Equivalent to java.lang.Character.isUpperCase() 
p{javaWhitespace} Equivalent to java.lang.Character.isWhitespace() 
p{javaMirrored} Equivalent to java.lang.Character.isMirrored() 
  
#Classes for Unicode scripts, blocks, categories and binary properties 
p{IsLatin} A Latin script character (script) 
p{InGreek} A character in the Greek block (block) 
p{Lu} An uppercase letter (category) 
p{IsAlphabetic} An alphabetic character (binary property) 
p{Sc} A currency symbol 
P{InGreek} Any character except one in the Greek block (negation) 
[p{L}&&[^p{Lu}]] Any letter except an uppercase letter (subtraction)
java类正则方法

Pattern类: 描述:必须首先将正则表达式(指定为字符串)编译为此类的实例。 然后将所得的图案可以被用来创建一个Matcher对象可以匹配任意character sequences针对正则表达式。 执行匹配的所有状态都驻留在匹配器中,所以许多匹配者可以共享相同的模式。

java.util.regex.Pattern 
#类定义
public final class Pattern
extends Object
implements Serializable


#类方法
public static Pattern compile(String regex) #将给定的正则表达式编译成模式。
#参数:regex -要编译的表达 
CANON_EQ 使正则等价。  
CASE_INSENSITIVE 启用不区分大小写匹配。  
COMMENTS 允许空格和注释模式。  
DOTALL 使dotall模式。  
LITERAL 启用模式的文本解析。  
MULTILINE 使多行模式。  
UNICODE_CASE 使用Unicode的折盒。  
UNICODE_CHARACTER_CLASS 使用Unicode版本的预定义字符类别和POSIX字符类。  
UNIX_LINES 使UNIX线模式。  

public static boolean matches(String regex,CharSequence input) #编译给定的正则表达式,并试图匹配给定的输入反对它。 
# Pattern.compile(regex).matcher(input).matches()  如果一个模式是要多次使用,编译它一次,并重用它将是更有效的比调用该方法,每一次。

public Matcher matcher(CharSequence input)  #创建一个匹配,将匹配给定的输入对该模式。

Matcher类:

描述:执行匹配操作在一个 character sequence通过解释 Pattern发动机(匹配适配器)。

匹配器是通过调用模式的matcher方法从模式创建。一旦创建匹配器可用于执行匹配操作三种不同:

  • 1.匹配整个输入序列与模式的matches方法的尝试。
  • 2.匹配输入序列的lookingAt方法的尝试,在起步之初对模式。
  • 3.find方法扫描输入序列寻找匹配模式下的子序列。
#语法结构
public final class Matcher
extends Object
implements MatchResult

#类常用方法
public boolean matches() #试图将整个区域与模式匹配。如果匹配成功则更多的信息可以通过start,end获得,并group方法。

public boolean find()  #试图找到匹配模式的输入序列中的下一个序列。匹配之后没有复位,在不匹配的第一个字符之前的比赛。如果匹配成功则更多的信息可以通过start,end获得,并group方法。

public String group()  #返回由以前的匹配输入序列。对于一个输入序列的匹配M,表达m.group()和s.substring(m start(), m.end())是等价的。

public String group(int group)  #返回被给定组以前的匹配操作在输入序列。 Capturing groups索引从左到右,在一开始。零组表示整个格局所以表达m.group(0)相当于m.group()。

public String group(String name)  #返回被给定的 named-capturing group之前匹配操作中的输入序列。在捕获组中设置了名称,向后引用的时候便可以直接调用该名称进行捕获调用 
groupCount

public int groupCount() #返回捕获组在这匹配的模式数。 组零表示的是整个模式的约定。它不包括在这个计数中。

String类正则匹配/替换

public boolean matches(String regex)   #告诉是否这个字符串匹配给定 regular expression (这str.matches(正则表达式)产生完全相同的结果的表达形式的方法调用)

public String replaceFirst(String regex,String replacement) #代替这个字符串的替换,给 regular expression匹配第一个字符串。 (与Pattern.compile(regex).matcher(str).replaceFirst(repl)形式相同)

public String replaceAll(String regex,String replacement) #每个子串替换该字符串的给予更换,给 regular expression比赛。 (与Pattern.compile(regex).matcher(str).replaceAll(repl) 形式相同)

public String[] split(String regex)  #将此字符串在给定的 regular expression比赛。 
public String[] split(String regex, int limit) #将此字符串在给定的 regular expression比赛,limit分割次数;

0x01 实际演示

案例演示1:

/**
 *  * a:非正则表达式实现 
    * b:正则表达式实现
	*    需求: 校验qq号码
    * 1:要求必须是5-15位数字
    * 2:0不能开头
    * 3:必须都是数字
 */
package com.weiyigeek.regex;
public class Demo1_Regex {
  public static void main(String[] args) {
    //示例1.采用非正则表达式实现 param1 String
    String str = new String("12345678");
    System.out.println("非正则验证匹配 :  "+notRegex(str));
    
    //示例2:正则方式String.matches()
    System.out.println("正则匹配结果 : " + str.matches("^[1-9]\d{4,14}"));
    System.out.println("正则匹配结果 : " + "01234579".matches("^[1-9]\d{4,14}"));
  }

  private static boolean notRegex(String str) {
    boolean flag = false;
    if(str.length() > 4 && str.length() < 16){
      if(!str.startsWith("0")) {
        char[] arr = str.toCharArray();
        for (int i = 0; i < arr.length; i++) {
          if(arr[i] > '0' && arr[i] < '9') {
            flag = true;
          }else {
            break;
          }
        }
      }
    }
    return flag;
  }
}

执行结果:

非正则验证匹配 : true
正则匹配结果 : true
正则匹配结果 : false

方法案例1:

//示例1.字符串分割采用正则表达式
strSpilt("I.LOVE.JAVA");
private static void strSpilt(String str) {
    String[] arr0 = str.split("\.");  //关键点 1
    String[] arr1 = str.split("[.]");  //关键点 2
    for (int i = 0; i < arr1.length; i++) {
        System.out.println(arr1[i]);
    }
    System.out.println("###########################");
}

//执行结果:
I
LOVE
JAVA

strSpiltInteger("91 48 75 76 82 10"); //字符串分割并且进行比较排序	
private static void strSpiltInteger(String st) {
    /**
        *  分析:
        * 1.将字符串转换成字符串数组
        * 2.将字符串转换成为数字并且存储在一个等长度的int数组中
        * 3.排序
        * 4.将排序后的结构钢遍历并拼接成为一个字符串;
        * */
    String[] sArr = st.split(" ");
    int[] iArr = new int[sArr.length]; //建立一个整形数组长度为字符串数组长度
    for (int i = 0; i < iArr.length; i++) {
        iArr[i] = Integer.valueOf(sArr[i]);  //将字符串转换成为数字
    }
    
    Arrays.sort(iArr);
    
    StringBuilder res = new StringBuilder();
    res.append("[ ");
    for (int i = 0; i < iArr.length; i++) {
        if( i == iArr.length - 1)
        {
            res.append(iArr[i] + " ]");
        }else{
            res.append(iArr[i] + " ");
        }
    }
    System.out.println(res);
}
//###########################
[ 10 48 75 76 82 91 ]

//示例2.正则表达式的替换功能(将数字替换掉)
System.out.println("字符串正则替换 : " + "We1iyi12Geek556".replaceAll("\d",""));
//###########################
字符串正则替换 : WeiyiGeek
正则表达式分组

正则表达式的分组功能,捕获组可以通过从左到右计算其开括号来编号。 例如在表达式 ((A)(B(C))) 中,存在四个这样的组:

1.((A)(B(C))) 
2.(A)
3.(B(C)) 
4.(C)

分组之后我们可以利用向后引用元字符串显示被捕获的字符(十分实用);

基础示例:

package com.weiyigeek.regex;
public class Demo3_Regex {
  public static void main(String[] args) {
    //示例1.分组的使用(正则叠词) 开开心心,快快乐乐
    System.out.println("示例1-1 : " + "开开心心".matches("(.)\1(.)\2"));
    System.out.println("示例1-2 : " + "开心开心".matches("(..)\1"));
    
    //示例2.切割需求:请按照叠词切割: "sdqqfgkkkhjppppkl";
    String str = new String("sdqqfgkkkhjppppkl");
    String[] Arr = str.split("(.)\1+");
    for (int i = 0; i < Arr.length; i++) {
      System.out.println(Arr[i]);
    }
    
    //示例3.替换需求:我我....我...我.要...要要...要学....学学..学.编..编编.编.程.程.程..程将字符串还原成:“我要学编程”。
    String s1 = "我我....我...我.要...要要...要学....学学..学.编..编编.编.程.程.程..程";
    String res = s1.replaceAll("\.", "").replaceAll("(.)\1\1", "");  //方式1
    String res1 = s1.replaceAll("\.", "").replaceAll("(.)\1+", "$1");  //方式2 (这里采用$1代替捕获的值得学习)
    System.out.println(res + "n" + res1);
  }
}

执行结果:

示例1-1 : true
示例1-2 : true

sd
fg
hj
kl

我要学编程
我要学编程
Pattern正则类中的方法

基础示例:

package com.weiyigeek.regex;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Demo4_Regex {

  public static void main(String[] args) {
    //示例1.Pattern类的简单实用
    Pattern p = Pattern.compile("[a-z]+", Pattern.CASE_INSENSITIVE); //获取正则表达式不区分大小写 (方式1)
    Matcher m = p.matcher("AABBB"); //获取适配器
    boolean b1 = m.matches();  //判断是否能进行匹配
    boolean b2 = Pattern.compile("[a-z]+").matcher("AABBB").matches(); //方法2 链式匹配
    System.out.println("方式1 的结果 : " + b1);
    System.out.println("方式2 的结果 : " + b2);
    
    //示例2.Pattern和Matcher的结合使用进行 手机号正则匹配
    String s = "我的手机号是:18983441325, 曾经用过18487258412, 还用过18883420241";
    Matcher m1 = Pattern.compile("1[456789]\d{9}").matcher(s);
    //注意要先找再获取注意这里的find获取了一个便会从下一个位置进行查找
    System.out.println("提取到的电话号码:");
    while(m1.find())
      System.out.println(m1.group());
  }
}

执行结果:

方式1 的结果 : true
方式2 的结果 : false

提取到的电话号码:
18983441325
18487258412
18883420241