欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【年薪百万之IT界大神成长之路十四】Java中正则表达式的高级应用

程序员文章站 2022-02-06 11:34:30
...

 
【年薪百万之IT界大神成长之路十四】Java中正则表达式的高级应用愿你如阳光,明媚不忧伤。

 


1. Java 中的正则表达式

java.util.regex 正则表达式并不限于某一种语言,但是在每种语言中有细微的差别。Java中的概念对应正则表达式中的子表达式。Java中命名捕获组的语法格式:(?<自定义名>expr);正则表达式内引用\k<捕获组名称>

 


2. Pattern.class 模式类

pattern 对象是一个正则表达式的编译表示。Pattern 类没有公共构造方法。要创建一个 Pattern 对象,必须首先调用其公共静态编译方法,它返回一个 Pattern 对象。该方法接受一个正则表达式作为它的第一个参数。

返回值 函数 描述
Pattern compile(String regex) 将给定的正则表达式编译成模式
Pattern compile(String regex, int flags) 将给定的正则表达式编译成带修饰符1的模式
boolean matches(String regex, CharSequence input) 检测正则表达式是否匹配
int flags() 返回该模式的匹配标志
Matcher matcher(CharSequence input) 创建一个指定正则的匹配器
String pattern() 返回用于编译的正则表达式
String[] split(CharSequence input) 用指定的正则拆分字符串
String[] split(CharSequence input, int limit) 用指定的正则拆分字符串并返回指定阈值的数组
Stream<String> splitAsStream(final CharSequence input) 用指定的正则拆分字符串并返回一个流
  • 示例
*****************************************************************
	package com.it.god.controller;
	
	import java.util.regex.Pattern;
	import java.util.stream.Stream;
	
	public class Test {
	
	    public static void main(String[] args) {
	        String str = "It.God.Road";
	        String regex = "\\.";
	        Pattern pattern = Pattern.compile(regex);
	        String[] result = pattern.split(str, 2);
	        Stream<String> stream = pattern.splitAsStream(str);
	
	        for (String data : result) {
	            System.out.println(data);
	        }
	
	        stream.forEach(System.out::println);
	    }
	
	}
................................................................
・【CONSOLE-split】実行結果
	It
	God.Road
・【CONSOLE-splitAsStream】実行結果
	It
	God
	Road
*****************************************************************

 


3. Matcher.class 匹配器类

Matcher 对象是对输入字符串进行解释和匹配操作的引擎。与Pattern 类一样,Matcher 也没有公共构造方法。需要调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。

 

3.1 校验

返回值 函数 描述
boolean find() 尝试查找与该模式匹配的输入序列的下一个子序列
boolean find(int start) 重置此匹配器,然后尝试查找匹配该模式、从指定索引开始的输入序列的下一个子序列
boolean hasAnchoringBounds() 查询此匹配器的区域边界的锚定【锚定为 true】
boolean hasTransparentBounds() 查询此匹配器的区域边界的透明度【透明为 true】
boolean hitEnd() 如果在最后一次匹配中命中了输入的结尾,则为真
boolean lookingAt() 尝试将从区域开头开始的输入序列与该模式匹配
boolean matches() 尝试将整个区域与模式匹配
boolean requireEnd()2 如果更多的输入可以将一个正匹配变为负匹配,返回true
  • 示例
*****************************************************************
	package com.it.god.controller;
	
	import java.util.regex.Matcher;
	import java.util.regex.Pattern;
	
	public class RegexTest {
	    public static void main(String[] args) {
	        checkLookingAt("IT", "IT.God.Road");
	        checkLookingAt("God", "IT.God.Road");
	        System.out.println("-----------------------------------");
	
	        checkFind("IT", "IT.God.Road");
	        checkFind("God", "IT.God.Road");
	        System.out.println("-----------------------------------");
	
	        checkFindIndex("IT", "IT.God.Road", 1);
	        checkFindIndex("God", "IT.God.Road", 5);
	        checkFindIndex("Road", "IT.God.Road", 5);
	        System.out.println("-----------------------------------");
	
	        checkMatches("IT", "IT.God.Road");
	        checkMatches("God", "IT.God.Road");
	        checkMatches("IT.God.Road", "IT.God.Road");
	        System.out.println("-----------------------------------");
	
	        checkHitEnd("IT", "IT.God.Road");
	        checkHitEnd("Road", "IT.God.Road");
	        System.out.println("-----------------------------------");
	
	        checkRequireEnd("IT", "IT.God.Road");
	        checkRequireEnd("Road", "IT.God.Road");
	    }
	
	    private static void checkLookingAt(String regex, String content) {
	        Pattern p = Pattern.compile(regex);
	        Matcher m = p.matcher(content);
	        if (m.lookingAt()) {
	            System.out.println(content + "\tlookingAt: " + regex);
	        } else {
	            System.out.println(content + "\tnot lookingAt: " + regex);
	        }
	    }
	
	    private static void checkFind(String regex, String content) {
	        Pattern p = Pattern.compile(regex);
	        Matcher m = p.matcher(content);
	        if (m.find()) {
	            System.out.println(content + "\tfind: " + regex);
	        } else {
	            System.out.println(content + "\tnot find: " + regex);
	        }
	    }
	
	    private static void checkFindIndex(String regex, String content, int index) {
	        Pattern p = Pattern.compile(regex);
	        Matcher m = p.matcher(content);
	        if (m.find(index)) {
	            System.out.println(content + "\tfindIndex: " + regex);
	        } else {
	            System.out.println(content + "\tnot findIndex: " + regex);
	        }
	    }
	
	    private static void checkMatches(String regex, String content) {
	        Pattern p = Pattern.compile(regex);
	        Matcher m = p.matcher(content);
	        if (m.matches()) {
	            System.out.println(content + "\tmatches: " + regex);
	        } else {
	            System.out.println(content + "\tnot matches: " + regex);
	        }
	    }
	
	    private static void checkHitEnd(String regex, String content) {
	        Pattern p = Pattern.compile(regex);
	        Matcher m = p.matcher(content);
	        if (m.hitEnd()) {
	            System.out.println(content + "\thitEnd: " + regex);
	        } else {
	            System.out.println(content + "\tnot hitEnd: " + regex);
	        }
	    }
	
	    private static void checkRequireEnd(String regex, String content) {
	        Pattern p = Pattern.compile(regex);
	        Matcher m = p.matcher(content);
	        if (m.requireEnd()) {
	            System.out.println(content + "\trequireEnd: " + regex);
	        } else {
	            System.out.println(content + "\tnot requireEnd: " + regex);
	        }
	    }
	
	}
................................................................
・【CONSOLE】実行結果
	IT.God.Road	lookingAt: IT
	IT.God.Road	not lookingAt: God
	-----------------------------------
	IT.God.Road	find: IT
	IT.God.Road	find: God
	-----------------------------------
	IT.God.Road	not findIndex: IT
	IT.God.Road	not findIndex: God
	IT.God.Road	findIndex: Road
	-----------------------------------
	IT.God.Road	not matches: IT
	IT.God.Road	not matches: God
	IT.God.Road	matches: IT.God.Road
	-----------------------------------
	IT.God.Road	not hitEnd: IT
	IT.God.Road	not hitEnd: Road
	-----------------------------------
	IT.God.Road	not requireEnd: IT
	IT.God.Road	not requireEnd: Road
*****************************************************************

 

3.2 查找

返回值 函数 描述
int start() 返回前一个匹配的起始索引
int start(int group) 返回给定组(索引)在前一个匹配操作中捕获的子序列的起始索引
int start(String name) 返回给定组(名称)在前一个匹配操作中捕获的子序列的起始索引
int end() 返回最后一个匹配的字符之后的偏移量
int end(int group) 返回给定组(索引)在前一个匹配操作中捕获的子序列的最后一个字符之后的偏移量
int end(String name) 返回给定组(名称)在前一个匹配操作中捕获的子序列的最后一个字符之后的偏移量
int groupCount() 返回此匹配器模式中捕获组的数量
String group() 返回与前一个匹配项匹配的输入子序列
String group(int group) 返回给定组(索引)在前一个匹配操作中捕获的输入子序列
String group(String name) 返回给定组(名称)在前一个匹配操作中捕获的输入子序列
  • 示例
*****************************************************************
	package com.it.god.controller;
	
	import java.util.regex.Matcher;
	import java.util.regex.Pattern;
	
	public class RegexTest {
	    public static void main(String[] args) {
	
	        checkFind("IT(?<god>\\.God)(\\.Road)", "IT.God.Road.test");
	    }
	
	    private static void checkFind(String regex, String content) {
	        Pattern p = Pattern.compile(regex);
	        Matcher m = p.matcher(content);
	        if (m.find()) {
	            System.out.println(content + "\tfind: " + regex);
	            System.out.println("Group previous" + ":" + m.group());
	            System.out.println("Group count" + ":" + m.groupCount());
	            System.out.println("Group 0:" + m.group(0));
	            System.out.println("Group 1:" + m.group(1));
	            System.out.println("Group name:" + m.group("god"));
	            System.out.println("Group 2:" + m.group(2));
	            System.out.println("Group previous" + ":" + m.group());
	            System.out.println("Start 0:" + m.start(0) + " End 0:" + m.end(0));
	            System.out.println("Start 1:" + m.start(1) + " End 1:" + m.end(1));
	            System.out.println("Start 2:" + m.start(2) + " End 2:" + m.end(2));
	            System.out.println(content.substring(m.start(0), m.end(1)));
	        } else {
	            System.out.println(content + "\tnot find: " + regex);
	        }
	    }
	
	}
................................................................
・【CONSOLE】実行結果
	IT.God.Road	find: IT(?<god>\.God)(\.Road)	-- 整个正则
	Group previous:IT.God.Road					-- 前一个匹配项的匹配子序列
	Group count:2								-- 共有两个分组
	Group 0:IT.God.Road							-- 分组0为整个表达式
	Group 1:.God								-- 分组1为第一个子表达式
	Group name:.God								-- 分组名为"name"的分组为第一个子表达式
	Group 2:.Road								-- 分组2为第二个子表达式
	Group previous:IT.God.Road					-- 前一个匹配项的匹配子序列
	Start 0:0 End 0:11							-- 整体的起止索引
	Start 1:2 End 1:6							-- 分组1的起止索引
	Start 2:6 End 2:11							-- 分组2的起止索引
	Start:0 End:11								-- 前一个匹配的起止索引(Group previous)
	IT.God										-- 整体到分组1结束截取的字符串
*****************************************************************

 

3.3 替换

appendReplacement() 和 appendTail() 两个方法一起使用可以达到 replaceAll() 和 replaceFirst() 的功能,replaceAll() 源码就是用这个两个方法实组合现的。

返回值 函数 描述
String quoteReplacement(String s) 将特殊字符替换为转义字符(即遇到\\ $就在前面加一个转义字符)
Matcher appendReplacement(StringBuffer sb, String replacement) 将匹配的第一个序列替换为指定字符,并将结果追加到StringBuffer中
Matcher appendReplacement(StringBuilder sb, String replacement) 将匹配的第一个序列替换为指定字符,并将结果追加到StringBuilder中
StringBuffer appendTail(StringBuffer sb) 把匹配到内容之后的字符串追加到StringBuffer中
StringBuilder appendTail(StringBuilder sb) 把匹配到内容之后的字符串追加到StringBuilder中
String replaceAll(String replacement) 用指定字符替换所有匹配的字符序列
String replaceAll(Function<MatchResult, String> replacer) 用指定函数返回的正则替换所有匹配的字符序列
String replaceFirst(String replacement) 用指定字符替换第一个匹配的字符序列
String replaceFirst(Function<MatchResult, String> replacer) 用指定函数返回的正则替换第一个匹配的字符序列
Matcher useAnchoringBounds(boolean b) 为这个匹配器设置区域边界的锚定
Matcher usePattern(Pattern newPattern) 改变匹配器用于查找匹配的模式
Matcher useTransparentBounds(boolean b) 为这个匹配器设置区域边界的透明度
Matcher reset() 重置匹配器
Matcher reset(CharSequence input) 重置匹配器并返回指定输入序列的匹配器
Matcher region(int start, int end) 设置匹配器的匹配区域
int regionStart() 匹配器区域的起始点
int regionEnd() 匹配器区域的结束点
Stream<MatchResult> results() 匹配结果的连续流,匹配结果都由 toMatchResult() 产生
MatchResult toMatchResult() 返回匹配器的匹配状态
  • 示例
*****************************************************************
	package com.it.god.controller;
	
	import java.util.regex.Matcher;
	import java.util.regex.Pattern;
	
	public class RegexTest2 {
	    public static void main(String[] args) {
	        checkReplaceAll("\\.", "IT.God.Road", "-");
	        checkReplaceFirst("\\.", "IT.God.Road", "-");
	        checkAppendReplacementTail("\\.", "IT.God.Road", "-");
	        checkQuoteReplacement("R\\w*d", "IT.God.Road", "${Road}");
	        checkRegion("\\.", "IT.God.Road", 2);
	        checkToMatchResult("\\.", "IT.God.Road", "-");
	
	    }
	
	    private static void checkReplaceAll(String regex, String content, String replacement) {
	        Pattern p = Pattern.compile(regex);
	        Matcher m = p.matcher(content);
	        if (m.find()) {
	            System.out.println(content + "\treplaceAll: " + m.replaceAll(replacement));
	        } else {
	            System.out.println(content + "\tnot replaceAll: " + regex);
	        }
	    }
	
	    private static void checkReplaceFirst(String regex, String content, String replacement) {
	        Pattern p = Pattern.compile(regex);
	        Matcher m = p.matcher(content);
	        if (m.find()) {
	            System.out.println(content + "\treplaceFirst: " + m.replaceFirst(replacement));
	        } else {
	            System.out.println(content + "\tnot replaceFirst: " + regex);
	        }
	    }
	
	    private static void checkAppendReplacementTail(String regex, String content, String replacement) {
	        Pattern p = Pattern.compile(regex);
	        Matcher m = p.matcher(content);
	        StringBuffer sb = new StringBuffer();
	        if (m.find()) {
	            m.appendReplacement(sb, replacement);
	            System.out.println(content + "\tappendReplacement: " + sb);
	        }
	        m.appendTail(sb);
	        System.out.println(content + "\tsappendTail: " + sb);
	    }
	
	    private static void checkQuoteReplacement(String regex, String content, String replacement) {
	        Pattern p = Pattern.compile(regex);
	        Matcher m = p.matcher(content);
	        if (m.find()) {
	            System.out.println(content + "\tquoteReplacement: " + m.replaceAll(m.quoteReplacement(replacement)));
	        }
	    }
	
	    private static void checkRegion(String regex, String content, int end) {
	        Pattern p = Pattern.compile(regex);
	        Matcher m = p.matcher(content);
	        m.region(0, end);
	        if (m.find()) {
	            System.out.println(content + "\tregion: " + m.regionStart());
	        } else {
	            System.out.println(content + "\tnot region: " + m.regionStart());
	        }
	    }
	
	    private static void checkToMatchResult(String regex, String content, String replacement) {
	        Pattern p = Pattern.compile(regex);
	        Matcher m = p.matcher(content);
	        System.out.println(content + "\ttoMatchResult: " + m.toMatchResult());
	        System.out.println(content + "\tresults: " + m.results());
	    }
	}

................................................................
・【CONSOLE】実行結果
	IT.God.Road	replaceAll: IT-God-Road
	IT.God.Road	replaceFirst: IT-God.Road
	IT.God.Road	appendReplacement: IT-
	IT.God.Road	sappendTail: IT-God.Road
	IT.God.Road	quoteReplacement: IT.God.${Road}
	IT.God.Road	not region: 0
	IT.God.Road	toMatchResult: java.util.regex.Matcher$ImmutableMatchResult@3c679bde
	IT.God.Road	results: java.util.stream.ReferencePipeline$Head@65e579dc
・【CONSOLE-Exception】実行結果
	Exception in thread "main" java.lang.IllegalArgumentException: No group with name {Road}
		at java.base/java.util.regex.Matcher.appendExpandedReplacement(Matcher.java:1060)
		at java.base/java.util.regex.Matcher.appendReplacement(Matcher.java:998)
		at java.base/java.util.regex.Matcher.replaceAll(Matcher.java:1182)
		at com.it.god.controller.RegexTest2.checkQuoteReplacement(RegexTest2.java:51)
		at com.it.god.controller.RegexTest2.main(RegexTest2.java:11)

*****************************************************************

 


4. PatternSyntaxException 异常类

PatternSyntaxException 是一个非强制异常类,它表示一个正则表达式模式中的语法错误。

返回值 函数 描述
String getDescription() 获取错误的描述
int getIndex() 获取错误的索引
String getMessage() 获取完整的详细信息
String getPattern() 获取错误的正则表达式模式
  • 示例
*****************************************************************
	package com.it.god.controller;
	
	import java.util.regex.Matcher;
	import java.util.regex.Pattern;
	import java.util.regex.PatternSyntaxException;
	
	public class RegexTest2 {
	    public static void main(String[] args) {
	        checkPatternSyntaxException("[", "IT.God.Road", "${Road}");
	    }
	    private static void checkPatternSyntaxException(String regex, String content, String replacement) {
	        try {
	            Pattern p = Pattern.compile(regex);
	            Matcher m = p.matcher(content);
	            m.replaceAll(replacement);
	        } catch (PatternSyntaxException e) {
	            System.out.println("PatternSyntaxException: ");
	            System.out.println("Description: " + e.getDescription());
	            System.out.println("Index: " + e.getIndex());
	            System.out.println("Message: " + e.getMessage());
	            System.out.println("Pattern: " + e.getPattern());
	        }
	    }
................................................................
・【CONSOLE】実行結果
	PatternSyntaxException: 
	Description: Unclosed character class
	Index: 0
	Message: Unclosed character class near index 0
	[
	^
	Pattern: [
*****************************************************************

 


【每日一面】

给一个连字符串 it_god_road 转化成驼峰形式

分析:题目要求将 it_god_road 转换为 itGodRoad,即连字符后面的第一个字母大写。
思路:将_和后面的小写字母替换为对应的大写字母。

*****************************************************************
	package com.it.god.controller;
	
	import java.util.regex.Matcher;
	import java.util.regex.Pattern;
	
	public class RegexTest2 {
	    public static void main(String[] args) {
	        checkInterview("(_)(.)", "it_god_road");
	    }
	    
	    private static void checkInterview(String regex, String content) {
	        Pattern p = Pattern.compile(regex);
	        Matcher m = p.matcher(content);
	        StringBuffer sb = new StringBuffer();
	        
	        while (m.find()) {
	            m.appendReplacement(sb, m.group(2).toUpperCase());
	        }
	        
	        m.appendTail(sb);
	        System.out.println(sb);
	    } 
	}
................................................................
・【CONSOLE】実行結果
	itGodRoad
*****************************************************************	

  1. public static final int CASE_INSENSITIVE = 0x02;
    public static final int DOTALL = 0x20;
    public static final int MULTILINE = 0x08;
    public static final int UNICODE_CASE = 0x40;
    ↩︎

  2. 如果这个方法返回true,并且找到了匹配项,那么更多的输入可能会导致匹配项丢失。如果这个方法返回false并且找到了匹配项,那么更多的输入可能会改变匹配项,但是匹配项不会丢失。如果没有找到匹配项,那么requireEnd就没有意义。 ↩︎