正则表达式

正则表达式对字符串的常见操作有:字符串的匹配、切割、替换、获取

正则表达式的构造摘要:

/*
正则表达式的构造摘要
构造 匹配

字符
x 字符 x
\\       反斜线字符
\0n      带有八进制值 0 的字符 n (0 <= n <= 7)
\0nn     带有八进制值 0 的字符 nn (0 <= n <= 7)
\0mnn    带有八进制值 0 的字符 mnn(0 <= m <= 3、0 <= n <= 7)
\xhh     带有十六进制值 0x 的字符 hh
\uhhhh   带有十六进制值 0x 的字符 hhhh
\t       制表符 ('\u0009')
\n       新行(换行)符 ('\u000A')
\r       回车符 ('\u000D')
\f       换页符 ('\u000C') 
\a       报警 (bell) 符 ('\u0007') 
\e       转义符 ('\u001B') 
\cx      对应于 x 的控制符 
  
字符类 
[abc]            a、b 或 c(简单类) 
[^abc]           任何字符,除了 a、b 或 c(否定) 
[a-zA-Z]         a 到 z 或 A 到 Z,两头的字母包括在内(范围) 
[a-d[m-p]]       a 到 d 或 m 到 p:[a-dm-p](并集) 
[a-z&&[def]]     d、e 或 f(交集) 
[a-z&&[^bc]]     a 到 z,除了 b 和 c:[ad-z](减去) 
[a-z&&[^m-p]]    a 到 z,而非 m 到 p:[a-lq-z](减去) 
  
预定义字符类 
.   任何字符(与行结束符可能匹配也可能不匹配) 
\d  数字:[0-9] 
\D  非数字: [^0-9] 
\s  空白字符:[ \t\n\x0B\f\r] 
\S  非空白字符:[^\s] 
\w  单词字符:[a-zA-Z_0-9] 
\W  非单词字符:[^\w] 
  
POSIX 字符类(仅 US-ASCII) 
\p{Lower} 小写字母字符:[a-z] 
\p{Upper} 大写字母字符:[A-Z] 
\p{ASCII} 所有 ASCII:[\x00-\x7F] 
\p{Alpha} 字母字符:[\p{Lower}\p{Upper}] 
\p{Digit} 十进制数字:[0-9] 
\p{Alnum} 字母数字字符:[\p{Alpha}\p{Digit}] 
\p{Punct} 标点符号:!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ 
\p{Graph} 可见字符:[\p{Alnum}\p{Punct}] 
\p{Print} 可打印字符:[\p{Graph}\x20] 
\p{Blank} 空格或制表符:[ \t] 
\p{Cntrl} 控制字符:[\x00-\x1F\x7F] 
\p{XDigit} 十六进制数字:[0-9a-fA-F] 
\p{Space} 空白字符:[ \t\n\x0B\f\r] 
  
java.lang.Character 类(简单的 java 字符类型) 
\p{javaLowerCase} 等效于 java.lang.Character.isLowerCase() 
\p{javaUpperCase} 等效于 java.lang.Character.isUpperCase() 
\p{javaWhitespace} 等效于 java.lang.Character.isWhitespace() 
\p{javaMirrored} 等效于 java.lang.Character.isMirrored() 
  
Unicode 块和类别的类 
\p{InGreek} Greek 块(简单块)中的字符 
\p{Lu} 大写字母(简单类别) 
\p{Sc} 货币符号 
\P{InGreek} 所有字符,Greek 块中的除外(否定) 
[\p{L}&&[^\p{Lu}]]  所有字母,大写字母除外(减去) 
  
边界匹配器 
^  行的开头 
$  行的结尾 
\b 单词边界 
\B 非单词边界 
\A 输入的开头 
\G 上一个匹配的结尾 
\Z 输入的结尾,仅用于最后的结束符(如果有的话) 
\z 输入的结尾 
  
Greedy 数量词 
X? X,     一次或一次也没有 
X* X,     零次或多次 
X+ X,     一次或多次 
X{n} X,   恰好 n 次 
X{n,} X,  至少 n 次 
X{n,m} X, 至少 n 次,但是不超过 m 次 
  
Reluctant 数量词 
X?? X,     一次或一次也没有 
X*? X,     零次或多次 
X+? X,     一次或多次 
X{n}? X,   恰好 n 次 
X{n,}? X,  至少 n 次 
X{n,m}? X, 至少 n 次,但是不超过 m 次 
  
Possessive 数量词 
X?+ X,     一次或一次也没有 
X*+ X,     零次或多次 
X++ X,     一次或多次 
X{n}+ X,   恰好 n 次 
X{n,}+ X,  至少 n 次 
X{n,m}+ X, 至少 n 次,但是不超过 m 次 
  
Logical 运算符 
XY   X 后跟 Y 
X|Y  X 或 Y 
(X)X,作为捕获组 
  
Back 引用 
\n 任何匹配的 nth 捕获组 

引用 
\ Nothing, 但是引用以下字符 
\Q Nothing,但是引用所有字符,直到 \E 
\E Nothing,但是结束从 \Q 开始的引用 
  
特殊构造(非捕获) 
(?:X) X,            作为非捕获组 
(?idmsux-idmsux)     Nothing,但是将匹配标志由 on 转为 off 
(?idmsux-idmsux:X)   X,作为带有给定标志 on - off 的非捕获组 
(?=X) X,            通过零宽度的正 lookahead 
(?!X) X,            通过零宽度的负 lookahead 
(?<=X) X,           通过零宽度的正 lookbehind 
(?<!X) X,           通过零宽度的负 lookbehind 
(?>X) X,            作为独立的非捕获组 

--------------------------------------------------------------------------------

反斜线、转义和引用 
反斜线字符 ('\') 用于引用转义构造,如上表所定义的,同时还用于引用其他将被解释为非转义构造的字符。因此,表达式 \\ 与单个反斜线匹配,而 \{ 与左括号匹配。 

在不表示转义构造的任何字母字符前使用反斜线都是错误的;它们是为将来扩展正则表达式语言保留的。可以在非字母字符前使用反斜线,不管该字符是否非转义构造的一部分。 

根据 Java Language Specification 的要求,Java 源代码的字符串中的反斜线被解释为 Unicode 转义或其他字符转义。因此必须在字符串字面值中使用两个反斜线,表示正则表达式受到保护,不被 Java 字节码编译器解释。例如,当解释为正则表达式时,字符串字面值 "\b" 与单个退格字符匹配,而 "\\b" 与单词边界匹配。字符串字面值 "hello" 是非法的,将导致编译时错误;要与字符串 (hello) 匹配,必须使用字符串字面值 "\\(hello\\)"。 

字符类 
字符类可以出现在其他字符类中,并且可以包含并集运算符(隐式)和交集运算符 (&&)。并集运算符表示至少包含其某个操作数类中所有字符的类。交集运算符表示包含同时位于其两个操作数类中所有字符的类。 

字符类运算符的优先级如下所示,按从最高到最低的顺序排列: 

1     字面值转义     \x 
2     分组 [...] 
3     范围 a-z 
4     并集 [a-e][i-u] 
5     交集 [a-z&&[aeiou]] 

注意,元字符的不同集合实际上位于字符类的内部,而非字符类的外部。例如,正则表达式 . 在字符类内部就失去了其特殊意义,而表达式 - 变成了形成元字符的范围。 

行结束符 
行结束符 是一个或两个字符的序列,标记输入字符序列的行结尾。以下代码被识别为行结束符: 

新行(换行)符 ('\n')、 
后面紧跟新行符的回车符 ("\r\n")、 
单独的回车符 ('\r')、 
下一行字符 ('\u0085')、 
行分隔符 ('\u2028') 或 
段落分隔符 ('\u2029)。 
如果激活 UNIX_LINES 模式,则新行符是惟一识别的行结束符。 

如果未指定 DOTALL 标志,则正则表达式 . 可以与任何字符(行结束符除外)匹配。 

默认情况下,正则表达式 ^ 和 $ 忽略行结束符,仅分别与整个输入序列的开头和结尾匹配。如果激活 MULTILINE 模式,则 ^ 在输入的开头和行结束符之后(输入的结尾)才发生匹配。处于 MULTILINE 模式中时,$ 仅在行结束符之前或输入序列的结尾处匹配。 

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

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

组零始终代表整个表达式。 
之所以这样命名捕获组是因为在匹配中,保存了与这些组匹配的输入序列的每个子序列。捕获的子序列稍后可以通过 Back 引用在表达式中使用,也可以在匹配操作完成后从匹配器检索。 
与组关联的捕获输入始终是与组最近匹配的子序列。如果由于量化的缘故再次计算了组,则在第二次计算失败时将保留其以前捕获的值(如果有的话)例如,将字符串 "aba" 与表达式 (a(b)?)+ 相匹配,会将第二组设置为 "b"。在每个匹配的开头,所有捕获的输入都会被丢弃。 
以 (?) 开头的组是纯的非捕获 组,它不捕获文本,也不针对组合计进行计数。
*/
View Code

1、字符串的匹配matches():

package Content;
/*
字符类
[abc]             a,b或者c(简单类)  --(对于只有一个字符时,[]可以省略,[1]<=>1)
[^abc]             任何字符,除了a,b,c(否定)
[a-zA-Z]         a 到 z 或 A 到 Z,两头的字母包括在内(范围)
[a-d[m-p]]         a 到 d 或 m 到 p:[a-dm-p](并集)
[a-z&&[def]]     d、e 或 f(交集)
[a-z&&[^bc]]     a 到 z,除了 b 和 c:[ad-z](减去) 
[a-z&&[^m-p]]   a 到 z,而非 m 到 p:[a-lq-z](减去)
PS:[0-9]<=>\d,举例:"1[378][0-9]{9}" =  "1[378]\\d{9}"。(在java中\需要用\来转义,所以写为\\d而不是\d)。 
 */
import java.util.*;

public class RegularExpression_matches {
    
    //匹配QQ号(长度为5-10位,纯数字组成,且不能以0开头)
    static boolean match(String string) {
        //定义匹配规则
        //第一位不能是0的纯数字,所以我们用[1-9]来表示第一位的规则;
        //第二位:我们用[0-9]来表示,后面是纯数字即[0-9],
        //qq的长度只能是5~10,而规则里我们用{}来表示范围,即[0-9]{4,9}结合起来就表示:4~9个纯数字。
        String regex = "[1-9][0-9]{4,9}";  
        //判断是否符合规则
        return string.matches(regex);
    }
    public static void main(String[] args) {
        String qq1 = "920783243";
        String qq2 = "020783243";
        String qq3 = "120783243";
        
        System.out.println(match(qq1));
        System.out.println(match(qq2));
        System.out.println(match(qq3));
        
    }
}
View Code

2、字符串の切割:split()

/*
    ***Greedy(贪婪) 数量词***
   *            重复零次或更多次
   +            重复一次或更多次
   ?            重复零次或一次
  {n}            重复n次
 {n,}            重复n次或更多次
 {n,m}            重复n到m次
 
   ***Reluctant(勉强) 数量词***
  X??            X, 一次或零次
  X*?            X, 零次或多次
  X+?            X,一次或多次
  X{n}?            X, 恰好n次
  X{n,}?        X, 至少n次
  X{n, m}?        X,至少n次, 但是不超过m次
    ***Possessive(占有)数量词 ***
  X?+            X, 一次或零次
  X*+            X, 零次或多次
  X++            X,一次或多次
  X{n}+            X, 恰好n次
  X{n,}+        X,至少n次
  X{n,m}+        X,至少n次, 但是不超过m次
*/
import java.util.*;

public class RegularExpression_split {
    static String[] strings;
    
    static void split(String string) {
        String regex = "@+";
        strings = string.split(regex);
        
    }
    public static void main(String[] args) {
        //切割字符串"Amy@@@Mike@@Alice@Johe".
        String string ="Amy@@@Mike@@Alice@Johe";
        strings = new String[10];
        
        split(string);
        
        for(String e:strings) {
            System.out.println(e);
        }
        
    }
}
View Code
package Content;
/*
 1、预定义字符类 :
    . 任何字符(与行结束符可能匹配也可能不匹配)
 2、组和捕获 
    捕获组可以通过从左到右计算其开括号来编号。例如,在表达式 ((A)(B(C))) 中,存在四个这样的组: 
     <1>((A)(B(C))) 
     <2>\A 
     <3>(B(C)) 
     <4>(C) 
组零始终代表整个表达式。 
  之所以这样命名捕获组是因为在匹配中,保存了与这些组匹配的输入序列的每个子序列。
  捕获的子序列稍后可以通过 Back 引用在表达式中使用,也可以在匹配操作完成后从匹配器检索。 
  与组关联的捕获输入始终是与组最近匹配的子序列。
  如果由于量化的缘故再次计算了组,则在第二次计算失败时将保留其以前捕获的值(如果有的话)
  例如,将字符串 "aba" 与表达式 (a(b)?)+ 相匹配,会将第二组设置为 "b"。在每个匹配的开头,所有捕获的输入都会被丢弃。 
  以 (?) 开头的组是纯的非捕获组,它不捕获文本,也不针对组合计进行计数。
 */
//PS:“haha.lisi.nihao”用"."来切割:这个小点可以代表任何字符,所以我们需要用转义字符\来将“.”转义为普通的点,所以只要把regex = "\\."即可。
public class RegularExpression_split2 {
    static String[] strings;
    static void split(String string) {
        //()来表示组,对组中的数据进行引用:
        //regex = "(.)\\1"就表示:
        //某一字符出现了两次((.)来表示任意字符,而\\1是对组(.)中的字符进行复用,合起来就是:两个相同的字符)
        //使用+号来表示出现多次,最终叠词就表示为:regex = "(.)\\1+"。
        String regex = "(.)\\1+";
        strings = string.split(regex);
    } 
    public static void main(String[] args) {
        //"Amy@@Alice¥¥MikezzzNancy"按叠词切割.
        String string  = "Amy@@Alice¥¥MikezzzNancy";
        
        split(string);
        
        for(String e:strings) {
            System.out.println(e);
        }
    }
}
View Code

3、字符串の替换:replaceAll()

package Content;

public class RegularExpression_replaceAll {

    public static void main(String[] args) {
        //将字符串“Amy@@Alice¥¥MikezzzNancy”中的叠词替换为:“、”。
        String string  = "Amy@@Alice¥¥MikezzzNancy";
        
        String regex = "(.)\\1+";
        String newString = string.replaceAll(regex, "、");
        
        System.out.println(newString);
        
    }

}
View Code
package Content;

public class RegularExpression_replaceAll2 {

    public static void main(String[] args) {
        //将字符串“Amy@@Alice¥¥MikezzzNancy”中的叠词替换为:“Amy@Alice¥MikezNancy”。
        String string  = "Amy@@Alice¥¥MikezzzNancy";
        
        String regex = "(.)\\1+";
        //使用$1来复用组中第1组的值(即叠词的字符)
        String newString = string.replaceAll(regex, "$1");
        
        System.out.println(newString);
        
    }

}
View Code

4、字符串的获取:

正则表达式其实是封装成了Pattern类,所以字符串的匹配、切割、替换都是调用了Pattern类中的方法。所以如果我们需要获取指定字符串中的子串,首先同样的我们需要进行字符串匹配,然后判断指定字符串中是否有匹配的子串,有就获取,没有就获取不到。

  获取子串的步骤:

  1、描述要获取的子串:匹配子串

  2、使用正则表达式的封装类Pattern来获取匹配器

  3、使用匹配器中的方法group()获取字符串的匹配的子串

 

package Content;

//获取字符串"Hello! I am Nancy,Nice to meet you!"中为5个字母的单词。即Hello、Nancy。
/*
第一步,我们要对子串进行匹配,即两个字母的单词,字母可以用[a-zA-Z]来表示,范围是两个,所以regex = "[a-zA-Z]{2}"。
但这样不够准确,我们需要的是单词,而不是三个字母,所以要用到“边界匹配器”
  边界匹配器 
  ^  行的开头 
  $  行的结尾 
  \b 单词边界 
  \B 非单词边界 
  \A 输入的开头 
  \G 上一个匹配的结尾 
  \Z 输入的结尾,仅用于最后的结束符(如果有的话) 
  \z 输入的结尾
*/
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegularExpression_get {
    public static void main(String[] args) {

        String string = "Hello! I am Nancy,Nice to meet you!";

        // 1、匹配子串
        String regex = "\\b[a-zA-Z]{5}\\b";

        // 2、获取匹配器
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(string);

        // 3、使用匹配器的group()方法来获取:(find方法是判断是否具有匹配子串)
        // start():返回当前匹配的子串的第一个字符在原目标字符串中的索引位置 。
        // end():返回当前匹配的子串的最后一个字符在原目标字符串中的索引位置 。
        // reset() 方法会重置Matcher 内部的 匹配状态。当find() 方法开始匹配时,Matcher 内部会记录截至当前查找的距离。调用reset() 会重新从文本开头查找。
        // 也可以调用 reset(CharSequence) 方法. 这个方法重置Matcher,同时把一个新的字符串作为参数传入,用于代替创建 Matcher的原始字符串。
        while (matcher.find()) {

            System.out.println(matcher.start() + " " + matcher.end());
            System.out.println(matcher.group());

        }
        
        String string1 = "Amy and Amy or Amy and andAmy";
        String regex1 = "Amy";

        pattern = pattern.compile(regex1);
        matcher = pattern.matcher(string1);
        
        System.out.println(matcher.lookingAt());  //lookingAt():检测目标字符串是否以匹配的子串起始。
//        System.out.println(matcher.groupCount());
        while (matcher.find()) {
            System.out.println(matcher.group());

        }
        
    }
}
View Code

 

 

 

 

 

posted @ 2019-10-06 22:00  七忆鱼  阅读(169)  评论(0编辑  收藏  举报