Java正则表达式(下)

本文详细介绍了Java中正则表达式的使用方法,包括Pattern和Matcher类的基本操作、各种匹配构造、字符类、预定义字符类等内容。通过丰富的示例代码帮助读者更好地理解和掌握Java正则表达式的应用。
摘要由CSDN通过智能技术生成

Pattern类:正则表达式的编译表示。

典型的调用顺序如下:

Pattern p = Pattern.compile("a*b");
Matcher m = p.matcher("aaaaab");
boolean b = m.matches();

在仅使用一次正则表达式时,可以方便地通过此类的matches方法。此方法编译表达式并在单个调用中将输入序列与其匹配。语句如下:

boolean b = Pattern.matches("a*b", "aaaaab");

这条语句相当于上面3条语句,但是对于重复的匹配而言它效率不高,因为它不允许重用已编译的模式。

注:此类的实例是不可变的,可供多个并发线程安全使用。Matcher类的实例用于多线程则不安全。

 

反斜杠,转义和引用

    反斜杠字符('\')用于引入如下表中定义的转义结构,以及引用字符,否则将被解释为非转义结构。因此,表达式\\匹配单个反斜杠,\ {匹配左括号。

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

    有必要在表示正则表达式的字符串文字中用双反斜杠,以保护它们不被Java字节码编译器解释。例如,字符串文字“\ b”在解释为正则表达式时匹配单个退格字符(U+0008),而“\\ b”匹配单词边界。字符串文字“\(hello\)”是非法的,并导致编译时错误;为了匹配字符串(hello),必须使用字符串文字“\\(hello \\)”。

下面这段对反斜杠的解释摘自https://segmentfault.com/q/1010000000431259 

普通反斜杠

    我们使用的反斜杠,就是一个 \

文艺反斜杠

    但是在java等编程语言中,我们需要使用转义:一个文艺反斜杠 \\ 表示一个普通反斜杠 \

二逼反斜杠

    正则表达式中,反斜杠也需要转义,即 \\ 表示匹配一个 \,然后蛋疼的事儿就来了,当你在 java中写 \\ 时,其实正则表达式引擎只接受到了一个 \,所以,如果你想让正则表达式引擎接受两个反斜杠,那么这两个斜杠都得转义。例如Pattern.matches("\\\\", "\\");返回true。

示例代码

Strings = "\u0009";
//1.替换为\u0009传递给正则表达式引擎,
boolean b = Pattern.matches("\t", s);
//1.替换为\t传递给正则表达式引擎,2.正则表达式解析器解释\t为\u0009
boolean b2 = Pattern.matches("\\t", s);
//1.替换为\\u0009传递给正则表达式引擎,2.正则表达式解析器解释\\u0009为\u0009
//在"\"之后的字符,正则表达式引擎认为如果不能被转义,则表示字符本身,即 "\\u0009"和"\u0009"是等价的  
boolean b3 = Pattern.matches("\\\t", s);
//1.替换为\\t传递给正则表达式引擎,2.正则表达式解析器解释\\t为\t
boolean b4 = Pattern.matches("\\\\t","\\t");

以上四个例子都会返回true. 当使用“\ t”时,转义序列\t由Java替换为字符U + 0009。 当使用“\\ t”时,\\ t中的转义序列\\被\替换为\,导致\ t被正则表达式解析器解释为字符U + 0009。因此,两种表示都将被正确解释。 这只是它被替换为相应的字符的时间问题。

正则表达式构造摘要

1.字符

构造

描述

x

字符x

Pattern.matches("a", "a");

\\

反斜杠字符

\0n

八进制值为0n的字符(0 <= n <= 7)

\0nn

八进制值为0nn(0 <= n <= 7)的字符。

Pattern.matches("\075", "=");//八进制75对应的十进制数为61,即字符“=”。

\0mnn

八进制值为0mnn的字符(0 <= m <= 3、0 <= n <= 7)。

Pattern.matches("\0144", "\f4");//此例子中,将\014看成了八进制,不知道为啥没把144当做八进制解释。

\xhh

十六进制值为0xhh的字符。

Pattern.matches("\\x61", "a");//十六进制61对应的十进制数为97,即小写字母“a”。

\uhhhh

十六进制值为hhhh的字符。

Pattern.matches("\u597D", "好");//汉字“好”对应的Unicode是597D

\x{h…h}

十六进制值为0xh ... h的字符(Character.MIN_CODE_POINT <=0xh...h<= Character.MAX_CODE_POINT)

\t

制表符 ('\u0009')。

Pattern.matches("\\t", "\u0009");

\n

换行符('\ u000A')

\r

回车字符('\u000D')

\f

换页字符('\ u000C')

\a

警报(铃声)字符('\ u0007')

\e

转义字符('\ u001B')

\cx

对应x的控制字符


2.字符类 

构造

描述

[abc]

一个字符集合。匹配方括号的中任意字符。你可以使用破折号(-)来指定一个字符范围。对于点(.)和星号(*)这样的特殊符号在一个字符集中没有特殊的意义。

String line="*add";
Pattern p = Pattern.compile("[abc*]");
Matcher m = p.matcher(line);

[^abc]

一个反向字符集。也就是说, 它匹配任何没有包含在方括号中的字符。你可以使用破折号(-)来指定一个字符范围。任何普通字符在这里都是起作用的。

例如,[^abc] 和 [^a-c] 是一样的。他们匹配"brisket"中得‘r’,也匹配“chop”中的‘h’。

String line="andmd";
Pattern p = Pattern.compile("[^a-c]");
Matcher m = p.matcher(line);

[a-zA-Z]

 

[a-d[m-p]]

等价于[a-dm-p],(并集)

[a-z&&[def]]

等价于[a-z&&def],(交集),结果是d、e或f

String line="abcd";
Pattern p = Pattern.compile("[a-d&&[b-g]]");
Matcher m = p.matcher(line);
System.out.println(m.find()+" "+m.group());

[a-z&&[^bc]]

a到z,除了b和c

[a-z&&[^m-p]]

a到z,除了m-p

String line="mabcd";
Pattern p = Pattern.compile("[a-z&&[^m-p]]");
Matcher m = p.matcher(line);
System.out.println(m.find()+" "+m.group());


3.预定义字符类 

构造

描述

.

匹配除了行终结符之外的任何单个字符。行终结符之后会描述。

\d

匹配一个数字

等价于[0-9]

\D

等价于[^0-9]

\h

匹配水平空白字符

[\t\xA0\u1680\u180e\u2000-\u200a\u202f\u205f\u3000]

\H

非水平空白字符:[^\h]

\s

空格字符:[\t\n\x0B\f\r]

\S

非空格字符:[^\s]

\v

垂直空格字符:[\n\x0B\f\r\x85\u2028\ u2029]

\V

非垂直空格字符:[^\v]

\w

等价于[A-Za-z0-9_]

\W

等价于[^A-Za-z0-9_]


行终结符 

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

        换行符字符('\ n'),

        回车字符后紧跟一个换行符(“\ r \ n”),

        一个独立的回车字符('\ r'),

        下一行字符('\ u0085'),

        分隔符字符('\ u2028')或

        段落分隔符字符('\ u2029)。

如果激活了UNIX_LINES模式,则唯一识别的行终止符是换行符\n。

正则表达式”.”匹配除了行终止符之外的任何字符,除非指定了DOTALL标志。

 

4.POSIX 字符类(仅 US-ASCII)

构造

描述

\p{Lower}

小写字母字符:[a-z]

Pattern.matches("\\p{Lower}", "m");

\p{Upper}

大写字母字符:[A-Z]

Pattern.matches("\\p{Upper}", "M");

\p{ASCII}

所有 ASCII:[\x00-\x7F]

Pattern.matches("\\p{ASCII}", "M");

\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{Black}

空格或制表符:[\t]

\p{Cntrl}

控制字符:[\x00-\x1F\x7F]

\p{XDigit}

十六进制数字:[0-9a-fA-F]

\p{Space}

空格字符:[\t\n\x0B\f\r]


开始ASCII只定义了128个字符编码,包括96个文字和32个控制符号,一共128个字符只需要一个字节的7位就能表示所有的字符,因此 ASCII 只使用了一个字节的后7位,最高位都为0。


5.java.lang.Character 类

构造

描述

\p{javaLowerCase}

等效于java.lang.Character.isLowerCase()

Pattern.matches("\\p{javaLowerCase}", "m");

\p{javaUpperCase}

等效于java.lang.Character.isUpperCase()

\p{javaWhitespace}

等效于java.lang.Character.isWhitespace()

\p{javaMirrored}

等效于java.lang.Character.isMirrored()


6.Unicode脚本,块,类别和二进制属性的类 

构造

描述

\p{IsLatin}

拉丁文字符(脚本)

\p{InGreek}

希腊语块的一个字符

\p{Lu}

大写字母(类别)

\p{IsAlphabetic}

字母字符(二进制属性)

\p{Sc}

货币符号

\P{InGreek}

除了希腊语块中字符的任何字符(否定)

[\p{L}&&[^\p{Lu}]]

除大写字母以外的任何字母(减法)


7.边界匹配器 

构造

描述

^

匹配行的开始。

$

匹配行的结束。

\b

匹配一个词的边界。一个词的边界就是一个词不被另外一个词跟随的位置或者不是另一个词汇字符前边的位置。注意,一个匹配的词的边界并不包含在匹配的内容中。

Pattern p = Pattern.compile("\\bm");
Matcher m = p.matcher("moon");
boolean b = m.find();//true
       
Matcher m2 = p.matcher("amoon");
boolean b2 = m2.find();//false

\B

匹配一个非单词边界。他匹配一个前后字符都是相同类型的位置:都是单词或者都不是单词。一个字符串的开始和结尾都被认为是非单词。

Pattern p = Pattern.compile("\\B..");
Matcher m = p.matcher("noonday");
boolean b = m.find();
       
Pattern p2 = Pattern.compile("y\\B.");
Matcher m2 =p2.matcher("possibly yesterday");
boolean b2 = m2.find();
       
System.out.println(b+" "+m.group());
System.out.println(b2+" "+m2.group());

\A

匹配输入的开始

\z    

输入的结尾

\G

上一次匹配的结束

import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class demo0 {
    public static void main(String args[])
    {
        Pattern p = Pattern.compile("\\Gdog");
        Matcher m = p.matcher("dogdog");
        booleanb =m.find();
        System.out.println(b+" "+" "+m.start()+" "+m.end()+" "+m.group());
        b = m.find();
        if(b)
        {
            System.out.println(b+" "+" "+m.start()+" "+m.end()+" "+m.group());
        }
        Pattern p2 = Pattern.compile("\\Gdog");
        Matcher m2 = p2.matcher("dog dog");
        booleanb2 =m2.find();
        System.out.println(b2+" "+" "+m2.start()+" "+m2.end()+" "+m2.group());
        b2 = m2.find();
        System.out.println(b2);
        if(b2)
        {
            System.out.println(b2+" "+" "+m2.start()+" "+m2.end()+" "+m2.group());
        }
    }
}

\Z

输入的结尾,仅用于最后的结束符(如果有的话)

import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class demo0 {
    public static void main(String args[])
    {
        Pattern p = Pattern.compile("StackOverflow\\Z");
        Matcher m = p.matcher("StackOverflow\n");
        booleanb =m.find();
        System.out.println(b+" "+" "+m.start()+" "+m.end()+" "+m.group());
       
        Pattern p2 = Pattern.compile("StackOverflow\\z");
        Matcher m2 = p2.matcher("StackOverflow");
        booleanb2 =m2.find();
        System.out.println(b2+" "+" "+m2.start()+" "+m2.end()+" "+m2.group());
    }
}


8.换行符匹配器

构造

描述

\R

任何Unicode换行序列,相当于\u000D\ u000A|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029]


9.贪婪量词(Greedy) 

Greedy数量词被称为“贪婪的”是因为匹配器被强制要求第一次尝试匹配时读入整个输入串,如果第一次尝试匹配失败,则从后往前逐个字符地回退并尝试再次匹配,直到匹配成功或没有字符可回退。

构造

描述

X?

匹配字符X,它出现0次或一次

X*

匹配字符X,它出现0次或多次

X+

匹配字符X,它出现1次或多次

X{n}

匹配字符X,它出现n次

X{n,}

匹配字符X,它至少出现n次

X{n,m}

匹配字符X,它出现至少n次,但是不超过m次


10.勉强的量词(Reluctant) 

Reluctant采用与Greedy相反的方法,它从输入串的首(字符)位置开始,在一次尝试匹配查找中只勉强地读一个字符,直到尝试完整个字符串。

构造

描述

X??

匹配字符X,它出现0次或一次

X*?

匹配字符X,它出现0次或多次

X+?

匹配字符X,它出现1次或多次

X{n}?

匹配字符X,它出现n次

X{n,}?

匹配字符X,它至少出现n次

X{n,m}?

匹配字符X,它出现至少n次,但是不超过m次


11.独占量词(Possessive) 

Possessive数量词总是读入整个输入串,尝试一次(仅且一次)匹配成功,不像Greedy,Possessive从不回退,即便这样做也可能使整体匹配成功。

构造

描述

X?+

匹配字符X,它出现0次或一次

X*+

匹配字符X,它出现0次或多次

X++

匹配字符X,它出现1次或多次

X{n}+

匹配字符X,它出现n次

X{n,}+

匹配字符X,它至少出现n次

X{n,m}+

匹配字符X,它出现至少n次,但是不超过m次


示例代码如下: 

import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public classdemo0 {
    public static void main(String args[])
    {
        //Greedy
        System.out.println("==Greedy===");
        Patternp = Pattern.compile(".*dog"); 
        Matcherm = p.matcher("aadogaaaadogaaaaaadog"); 
        while (m.find()) { 
           System.out.println(m.start() +" " +m.end()+" "+m.group()); 
        }
       
        //Reluctant
        System.out.println("==Reluctant===");
        Pattern p2 = Pattern.compile(".*?dog"); 
        Matcher m2 = p2.matcher("aadogaaaadogaaaaaadog"); 
        while (m2.find()) { 
           System.out.println(m2.start() +" " +m2.end()+" "+m2.group()); 
        }
       
        //Possessive
        System.out.println("==Possessive===");
        Pattern p3 = Pattern.compile(".*+dog"); 
        Matcherm3 = p3.matcher("aadogaaaadogaaaaaadog"); 
        while (m3.find()) { 
           System.out.println(m3.start() +" " +m3.end()+" "+m3.group()); 
        }
        
    }
}

12.逻辑运算符

构造

描述

XY

匹配字符串XY

X|Y

匹配X字符或Y字符

(X)

匹配 'x' 并且记住匹配项,就像下面的例子展示的那样。括号被称为捕获括号。

public static void main(String args[])
    {
        Pattern p = Pattern.compile("(foo) (bar) \\1 \\2");
        Matcher m = p.matcher("foo bar foo bar");
        booleanb =m.matches();
        System.out.println(b+" "+" "+m.start()+" "+m.end()+" "+m.group());
        
    }


13.返回引用 

构造

描述

\n

任何第n个匹配的捕获组

\k<name>

匹配任何命名捕获组“名称”


14.引用 

构造

描述

\

Nothing,但是引用以下字符

\Q

Nothing,但是引用所有字符,直到\E

\E

Nothing,但是结束从\Q开始的引用


15.特殊构造(命名捕获和非捕获) 

构造

描述

(?<name>X)

匹配字符X,作为命名捕获组

(?:X)

匹配 'x' 但是不记住匹配项。这种叫作非捕获括号,使得你能够定义为与正则表达式运算符一起使用的子表达式。来看示例表达式 (?:foo){1,2}。如果表达式是 foo{1,2},{1,2}将只对 ‘foo’ 的最后一个字符 ’o‘ 生效。如果使用非捕获括号,则{1,2}会匹配整个 ‘foo’ 单词。

import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class demo0 {
    public static void main(String args[])
    {
        Pattern p = Pattern.compile("(?:foo){2}");
        Matcher m = p.matcher("foofoo");
        booleanb = m.matches();
        System.out.println(b+" "+" "+m.start()+" "+m.end()+" "+m.group());
       
        Pattern p2 = Pattern.compile("foo{2}");
        Matcher m2 = p2.matcher("fooo");
        booleanb2 = m2.matches();
        System.out.println(b2+" "+" "+m2.start()+" "+m2.end()+" "+m2.group());
    }
}

(?idmsuxU-idmsuxU)

 

(?idmsux-idmsux:X)

 

Y(?=X)

正向肯定查找,匹配'Y'仅仅当'Y'后面跟着'X'

import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class demo0 {
    public static void main(String args[])
    {
        Pattern p = Pattern.compile("dog(?=foo)");
        Matcher m = p.matcher("dogfoo12");
        booleanb = m.find();
        System.out.println(b+" "+" "+m.start()+" "+m.end()+" "+m.group());
       
        Pattern p2 = Pattern.compile("dog(?=foo)");
        Matcher m2 =p2.matcher("dog12foo");
        booleanb2 = m2.find();
        System.out.println(b2);
    }
}

Y(?!X)

正向否定查找, 匹配'Y'仅仅当'Y'后面不跟着'X'.

import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class demo0 {
    public static void main(String args[])
    {
        Pattern p = Pattern.compile("dog(?!foo)");
        Matcher m = p.matcher("dogfoo12");
        booleanb = m.find();
        System.out.println(b);
       
        Pattern p2 = Pattern.compile("dog(?!foo)");
        Matcher m2 = p2.matcher("dog12foo");
        booleanb2 = m2.find();
        System.out.println(b2+" "+" "+m2.start()+" "+m2.end()+" "+m2.group());
    }
}

(?<=X)Y

反向肯定查找,匹配'Y'仅仅当'Y'前面是'X'.

import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class demo0 {
    public static void main(String args[])
    {
        Pattern p = Pattern.compile("(?<=foo)dog");
        Matcher m = p.matcher("foo12dog");
        booleanb = m.find();
        System.out.println(b);
       
        Pattern p2 = Pattern.compile("(?<=foo)dog");
        Matcher m2 = p2.matcher("12foodog");
        booleanb2 = m2.find();
        System.out.println(b2+" "+" "+m2.start()+" "+m2.end()+" "+m2.group());
    }
}

(?<!X)Y

反向否定查找,,匹配'Y'仅仅当'Y'前面不是'X'.

import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class demo0 {
    public static void main(String args[])
    {
        Pattern p = Pattern.compile("(?<!foo)dog");
        Matcher m =p.matcher("foo12dog");
        booleanb = m.find();
        System.out.println(b+" "+" "+m.start()+" "+m.end()+" "+m.group());
       
        Pattern p2 = Pattern.compile("(?<!foo)dog");
        Matcher m2 = p2.matcher("12foodog");
        booleanb2 = m2.find();
        System.out.println(b2);
    }
}

(?>X)

匹配字符X,作为独立的,非捕获组

   

参考文档:

http://docs.oracle.com/javase/8/docs/api/

http://blog.csdn.net/luoweifu/article/details/42759439

https://segmentfault.com/q/1010000000431259

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值