Java正则表达式学习与整理

一、正则表达式简介

(一)前言

      在Java程序设计课程中,在老师的引领下去自学了Java正则表达式的用法及内容,发现正则表达式应用范围非常比较广泛,如在利用Python来爬取数据时候,也会用上正则表达式,所以决定花点心思去学习一下正则表达式。以下为我学习的总结,如有错误,请大家指正!

(二)概念

      正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本

       在众多语言中都可以支持正则表达式,如Perl、PHP、Java、Python、Ruby等。当然在Java中也可以通过处理字符串的方式达到检索,替换文本字符串的目的,但是有了正则表达式写代码更加简洁,通常两三行代码就可以达到目的,当然这也是建立在熟悉正则表达式的基础之上的。

(三)特点

正则表达式的特点是:

  • 灵活性、逻辑性和功能性非常的强;
  • 可以迅速地用极简单的方式达到字符串的复杂控制。
  • 可读性比较差。

(四)组成

      Java正则表达式的类在 java.util.regex 包中,包括三个类:Pattern、Matcher 和 PatternSyntaxException。

  • Pattern对象是正则表达式的已编译版本。他没有任何公共构造器,我们通过传递一个正则表达式参数给公共静态方法 compile 来创建一个pattern对象。
  • Matcher是用来匹配输入字符串和创建的 pattern 对象的正则引擎对象。这个类没有任何公共构造器,我们用patten对象的matcher方法,使用输入字符串作为参数来获得一个Matcher对象。然后使用matches方法,通过返回的布尔值判断输入字符串是否与正则匹配。
  • 如果正则表达式语法不正确将抛出PatternSyntaxException异常。

(五)语法格式

/**
 * @author WXF
 * @data 2021-04-20
 * @description 语法格式
 */
//写正则表达式
String regex = "(.*)(\\d+)(.*)";
// 将给定的正则表达式编译到模式中。
Pattern pattern = Pattern.compile(regex);
//匹配字符串
Matcher matcher = pattern.matcher("This order was placed for QT3000! OK?");
matcher.find();   //得到matcher后可以使用一系列方法:find、group、replaceAll...

(六)正则表达式语法

  • 普通字符
正则表达式说明
[123abc]匹配[…]括号里边的所有字符,相当于匹配1或2或3或a或b或c, 等价于[1|2|3|a|b|c]
[^123abc]匹配除了[…]之外的所有字符,相当于匹配除了1,2,3,a,b,c之外的所有字符]
[a-z]表示一个区间,匹配小写字母
[A-Z]表示一个区间,匹配大写字母
[A-Z]表示一个区间,匹配大写字母
[0-9]表示一个区间,匹配0到9之间的数字
\d匹配数字,等价于[0-9]
\D匹配非数字,等价于[^0-9]
\w匹配字母、数字或者下划线,等价于[a-zA-z0-9_]
\W匹配非字母、非数字或者非下划线,\W相当于匹配\w的补集字符,等价于[^a-zA-z0-9_]

说明:\大写字母 和 \小写字母,匹配的字符内容是相反的,^代表取反的意思

  • 非打印字符
正则表达式说明
\cx匹配由x指明的控制字符。例如, \cM 匹配一个 control-M 或回车符。x 的值必须是26个字母
\f匹配一个换页符
\n匹配一个换行符
\r匹配一个回车符
\t匹配一个制表符
\v匹配一个垂直制表符
\s匹配所有的空白字符,等价于[\f\n\r\t\v]
\S匹配所有非空白字符,等价于[^\f\n\r\t\v]

说明:控制字符主要有LF(换行)、CR(回车)、FF(换页)、DEL(删除)、BS(退格)、BEL(振铃)等,存在于Ascii码中的第0~31号及127号中。
点击此链接可查看更多关于控制字符的内容:

  • 特殊字符
正则表达式说明
$匹配输入字符串的结尾位置,要匹配 $ 字符本身,请使用\$
( )标记一个子表达式的开始和结束位置,要匹配这些字符,请使用\( )
*匹配前面的子表达式零次或多次,要匹配 * 字符,请使用 \*
+匹配前面的子表达式一次或多次,要匹配 + 字符,请使用 \+
.匹配除换行符 \n 之外的任何单个字符,要匹配 . ,请使用 \.
[标记一个中括号表达式的开始。要匹配 [ ,请使用 \[.
?匹配前面的子表达式零次或一次,或指明一个非贪婪限定符,要匹配 ? 字符,请使用 ?
\将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符
^匹配输入字符串的开始位置,当该符号在方括号表达式中使用时,匹配非方括号内容的字符,相当于取反,要匹配 ^ 字符本身,请使用 ^
{标记限定符表达式的开始,要匹配 {,请使用 \{
|指明两项之间的一个选择,相当于或,要匹配|,请使用\
  • 限定字符
正则表达式说明
{n}n 是一个非负整数,匹配确定的 n 次
{n,}n 是一个非负整数,至少匹配n 次
{n,m}m 和 n 均为非负整数,其中n <= m,最少匹配 n 次且最多匹配 m 次

二、正则表达式的运用

      正则表达式的运用包括:字符串匹配、字符串的切分、字符串的替换、和字符串的捕获,如下给出各用法的代码和示例,最后通过综合示例再次带大家理解正则表达式的使用。

(一) 字符串匹配

      matches 和lookingAt 方法都用来尝试匹配一个输入序列模式。
      它们的不同是matcher要求整个序列都匹配,而lookingAt 不要求。这两个方法经常在输入字符串的开始使用。Matcher判断整个字符序列与模式是否匹配。当连续用Matcher对象检查多个字符串时候,可以使用Matcher.reset():重置匹配器,放弃其所有显式状态信息并将其添加位置设置为零。也可以使用Matcher.reset(CharSequence input) 重置此具有新输入序列的匹配器来重复使用匹配器。

/**
 * @author WXF
 * @data 2021-04-20
 * @description 字符串匹配
 */
//匹配功能
String telphone = "17612345678";
//[358]表示这个字符是3、5或8,[0-9]表示这个字符为0到9,{9}表示出现正好9次
String regex = "1[358][0-9]{9}";
//匹配,返回值为布尔类型(也就是判断字符串是否符合这个正则表达式)
boolean flag = telphone.matches(regex);
System.out.println(flag);
 
String str = "heheeeeeeeeeee";
//+号表示e出现1次或者多次
String regex1 = "hehe+";
//判断是否匹配
boolean matches = str.matches(regex1);
System.out.println(matches);

打印结果如下:

false
true
/**
 * @author WXF
 * @data 2021-04-20
 * @description 字符串匹配
 */
public class RegexMatches {
    private static final String REGEX = "foo";
    private static final String INPUT = "fooooooooooooooooo";
    private static Pattern pattern;
    private static Matcher matcher;
 
    public static void main(String args[]) {
        pattern = Pattern.compile(REGEX);
        matcher = pattern.matcher(INPUT);
 
        System.out.println("Current REGEX is: " + REGEX);
        System.out.println("Current INPUT is: " + INPUT);
 
        System.out.println("lookingAt(): " + matcher.lookingAt());
        System.out.println("matches(): " + matcher.matches());
    }
}

打印结果如下:

Current REGEX is: foo
Current INPUT is: fooooooooooooooooo
lookingAt(): true
matches(): false

(二)字符串的切分

String[] split(String regex)

根据给定的正则表达式的匹配来拆分此字符串。

String[] split(String regex, int limit)

根据匹配给定的正则表达式来拆分此字符串。

      当然,还有一个StringTokenizer类,可以用来切分字符串,但是现在SUN已经不推荐使用了。转变下思路,其实用正则表达式也可以达到将字符串切分为段的目的。

简单的:

String str = "one:two:three:four:five";
//使用 : 符号分割字符串
String[] split = str.split(":");
for (String s : split) {
    System.out.println(s);
}

打印结果如下:

one
two
three
four
five

较为复杂的:

// 使用 Pattern split() method
// "\\W": 表示非[a-zA-Z_0-9]的字符
Pattern pattern = Pattern.compile("\\W");
String[] words = pattern.split("one@two#three:four$five");
//遍历打印
for (String s : words) {
    System.out.println("Pattern.split  : " + s);
}

打印结果如下:

Pattern.split  : one
Pattern.split  : two
Pattern.split  : three
Pattern.split  : four
Pattern.split  : five

(三)字符串的替换

String.replace(char oldChar, char newChar)

返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 而生成的。

String.replace(CharSequence target, CharSequence replacement)

使用指定的字面值替换序列替换此字符串匹配字面值目标序列的每个子字符串。

String.replaceAll(String regex, String replacement)

使用给定的 replacement 字符串替换此字符串匹配给定的正则表达式的每个子字符串。

String.replaceFirst(String regex, String replacement)

使用给定的 replacement 字符串替换此字符串匹配给定的正则表达式的第一个子字符串。

StringBuffer.replace(int start, int end, String str)

使用给定 String 中的字符替换此序列的子字符串中的字符。

StringBuilder.replace(int, int, java.lang.String)

使用给定 String 中的字符替换此序列的子字符串中的字符。

Matcher.replaceAll(String replacement)

替换模式与给定替换字符串相匹配的输入序列的每个子序列。

Matcher.replaceFirst(String replacement)

替换模式与给定替换字符串匹配的输入序列的第一个子序列。

简单的:

String str = "one:two:three:four:five";
//使用 : 符号分割字符串
String s1 = str.replace(":","000");
//第一个参数为正则表达式
String s2 = str.replaceAll(":", "000");
System.out.println(s1);
System.out.println(s2);

打印结果如下:

one000two000three000four000five
one000two000three000four000five

较复杂的:

// "\\W": 表示非[a-zA-Z_0-9]的字符
Pattern pattern = Pattern.compile("\\W");
Matcher matcher = pattern.matcher("one@two#three:four$five");
//替换匹配到的第一个
System.out.println(matcher.replaceFirst("000"));
//替换匹配到的所有元素
System.out.println(matcher.replaceAll("000"));

打印结果如下:

one000two#three:four$five
one000two000three000four000five

      appendReplacement 和 appendTail 方法

      Matcher 类也提供了appendReplacement 和appendTail 方法用于文本替换:

      看下面的例子来解释这个功能:

/**
 * @author WXF
 * @data 2021-04-20
 * @description appendReplacement 和 appendTail 方法
 */
public class RegexMatches1
{
    private static String REGEX = "a*b";
    private static String INPUT = "aabfooaabfooabfoob";
    private static String REPLACE = "-";
    public static void main(String[] args) {
        Pattern p = Pattern.compile(REGEX);
        // 获取 matcher 对象
        Matcher m = p.matcher(INPUT);
        StringBuffer sb = new StringBuffer();
        while(m.find()){
            //替换
            m.appendReplacement(sb,REPLACE);
        }
        m.appendTail(sb);
        System.out.println(sb.toString());
    }
}

打印结果如下:

-foo-foo-foo-

(四)字符串的捕获

      捕获组是把多个字符当一个单独单元进行处理的方法,它通过对括号内的字符分组来创建。

      例如,正则表达式(dog) 创建了单一分组,组里包含"d",“o”,和"g"。

      捕获组是通过从左至右计算其开括号来编号。例如,在表达式((A)(B(C))),有四个这样的组:

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

      可以通过调用matcher对象的groupCount方法来查看表达式有多少个分组。groupCount方法返回一个int值,表示matcher对象当前有多个捕获组。

      还有一个特殊的组(组0),它总是代表整个表达式。该组不包括在groupCount的返回值中。

/**
 * @author WXF
 * @data 2021-04-20
 * @description 字符串捕获
 */
//group用法
public class RegexMatches {
    public static void main(String args[]) {
 
        // 按指定模式在字符串查找
        String line = "This order was placed for QT3000! OK?";
        String pattern = "(.*)(\\d+)(.*)";
 
        // 创建 Pattern 对象
        Pattern r = Pattern.compile(pattern);
 
        // 现在创建 matcher 对象
        Matcher m = r.matcher(line);
        System.out.println(m.groupCount());
        if (m.find()) {
            System.out.println("Found value: " + m.group(0));
            System.out.println("Found value: " + m.group(1));
            System.out.println("Found value: " + m.group(2));
        } else {
            System.out.println("NO MATCH");
        }
    }
}
/**
 * @author WXF
 * @data 2021-04-20
 * @description 字符串捕获
 */
private static void test2() {
    String str = "aa1234bb7672cc";
 
    //1:对指定规则进行编译,获取一个模式对象
    Pattern compile = Pattern.compile("aa(\\d+)bb([0-9]+)cc");
    //2:使用这个模式对字符串进行匹配,返回一个匹配的对象
    Matcher matcher = compile.matcher(str);
    //3:使用这个macher对象,可以具体的进行匹配操作,然后获取匹配的结果
    if(matcher.find()){
        String group = matcher.group();
        String group2 = matcher.group(0);//和不传参数一样,都是获取整个正则表达式匹配的内容
        String group3 = matcher.group(1);//获取正则表达式中第一个正则组的内容
        String group4 = matcher.group(2);//.......
        System.out.println("group:"+group);
        System.out.println("group2:"+group2);
        System.out.println("group3:"+group3);
        System.out.println("group4:"+group4);
    }
}

打印结果如下:

group:aa1234bb7672cc
group2:aa1234bb7672cc
group3:1234
group4:7672

(五)综合示例

/**
 * @author WXF
 * @data 2021-04-20
 * @description 综合示例
 */
public class RegexExamples {
 
    public static void main(String[] args) {
        // 使用 pattern with flags
        Pattern pattern = Pattern.compile("ab", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher("ABcabdAb");
 
        // 使用 Matcher find(), group(), start() 和 end() 方法
        while (matcher.find()) {
            System.out.println("Found the text \"" + matcher.group()
                    + "\" starting at " + matcher.start()   //匹配到的元素的开始下标索引
                    + " index and ending at index " + matcher.end());   //匹配到的元素截止下标索引加1
        }
 
        // 使用 Pattern split() 方法
        pattern = Pattern.compile("\\W");
        String[] words = pattern.split("one@two#three:four$five");
        for (String s : words) {
            System.out.println("Split using Pattern.split(): " + s);
        }
 
        // 使用 Matcher.replaceFirst() 和 replaceAll() 方法
        //  *号表示前面的1出现0次或者多次
        pattern = Pattern.compile("1*2");
        matcher = pattern.matcher("11234512678");
        //使用 _ 号替换掉所有匹配到的元素
        System.out.println("Using replaceAll: " + matcher.replaceAll("_"));
        //使用 _ 号替换掉第一个匹配到的元素
        System.out.println("Using replaceFirst: " + matcher.replaceFirst("_"));
 
        //使用 capturing group
        //   \\1 表示第一组:(\\w\\d)的简写
        System.out.println(Pattern.matches("(\\w\\d)\\1", "a2a2")); //true
        System.out.println(Pattern.matches("(\\w\\d)\\1", "a2b2")); //false
        //   \\2 表示第二组:(B\\d)的简写   \\1 表示第一组:(AB)的简写
        System.out.println(Pattern.matches("(AB)(B\\d)\\2\\1", "ABB2B2AB")); //true
        System.out.println(Pattern.matches("(AB)(B\\d)\\2\\1", "ABB2B3AB")); //false
    }
 
}

打印结果:

Found the text "AB" starting at 0 index and ending at index 2
Found the text "ab" starting at 3 index and ending at index 5
Found the text "Ab" starting at 6 index and ending at index 8
Split using Pattern.split(): one
Split using Pattern.split(): two
Split using Pattern.split(): three
Split using Pattern.split(): four
Split using Pattern.split(): five
Using replaceAll: _345_678
Using replaceFirst: _34512678
true
false
true
False

三、异常

(一) PatternSyntaxException 类的方法

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

      PatternSyntaxException 类提供了下面的方法来帮助我们查看发生了什么错误。

public String getDescription()

获取错误的描述。

public int getIndex()

获取错误的索引。

public String getPattern()

获取错误的正则表达式模式。

public String getMessage()

      返回多行字符串,包含语法错误及其索引的描述、错误的正则表达式模式和模式中错误索引的可视化指示。

四、总结

      上述就是我对Java正则表达式的学习和整理,提到的内容可能偏少或有错误,但都是比较实用的示例。希望这篇文章会对你有帮助,如果有什么问题欢迎在评论区提出。

五、引用

  1. https://www.cnblogs.com/xyou/p/7427779.html
  2. https://blog.csdn.net/sxdtzhp/article/details/50993571
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值