欢迎来真孝善网,为您提供真孝善正能量书籍故事!

深入解析Java中的正则表达式应用技巧

时间:11-15 神话故事 提交错误

大家好,关于深入解析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)); }

用户评论

麝香味

我一直觉得正则表达式好强大,可惜我学不会啊

    有16位网友表示赞同!

烟花巷陌

之前遇到个很麻烦的数据处理问题,幸好找到了Java正则表达式的解决方案

    有12位网友表示赞同!

千城暮雪

最近在学习Java开发,正则表达式这一块感觉有点搞不懂

    有8位网友表示赞同!

见朕骑妓的时刻

想问一下,用Java正则表达式怎么匹配中英文混合的字符串?

    有13位网友表示赞同!

孤单*无名指

有没有推荐资料或者教程可以帮助我入门Java正则表达式?

    有15位网友表示赞同!

莫阑珊

学习Java正好碰到正则表达式的学习,感觉很有潜力

    有12位网友表示赞同!

颓废i

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位网友表示赞同!

【深入解析Java中的正则表达式应用技巧】相关文章:

1.蛤蟆讨媳妇【哈尼族民间故事】

2.米颠拜石

3.王羲之临池学书

4.清代敢于创新的“浓墨宰相”——刘墉

5.“巧取豪夺”的由来--米芾逸事

6.荒唐洁癖 惜砚如身(米芾逸事)

7.拜石为兄--米芾逸事

8.郑板桥轶事十则

9.王献之被公主抢亲后的悲惨人生

10.史上真实张三丰:在棺材中竟神奇复活