Java正则表达式基础

正则表达式是跨语言的,并没有Java啊C的区分,这里除了将一下正则表达式的基础,另外再讲一下正则表达式在Java中的使用,比如与之相关的某些类。

1 定义

正则表达式(regular expression)用于指定字符串的模式,它由一些特殊的字符语法组成,可以匹配某种特定模式的字符串。简单地说,正则表达式就是特定的语法写的一个特殊字符串,然后看我们平时的普通字符串,比如电话号码、身份证号、邮箱是否符合这个特定字符串的规则,符合就选中,不符合就淘汰。

2 语法

语法解释
字符单个字符
c

\unnn,\xnn,\0n,\0nn,\0nnn
\t,\n,\r,\f,\a,\e

\cc
字符本身

具有给定十六进制或十进制值的码元

控制符:制表符、换行符、回车符、换页符、警告符、逃逸符

与字符c相关的控制类
字符类字符类是一个括在括号中的可选择的字符集。例如,[Jj]代表J或者j,[A-Za-z]代表所有大小写字母,[0-9]代表所有数字。这里“-”表示以恶范围(所有Unicode值落在两个边界范围之内的字符)
[AB…]

[^…]

[…&&…]
任何由A、B…表示的字符,如正则:[Bb[0-9]],匹配:B(或b或数字)

字符集的补集,如正则:[^0-9],匹配:非数字

两个字符集的交集,如正则:[a-g&&d-n],匹配:字母d或e或f或g
预定义字符类预定义字符类在Java中反单斜杠”\”要写成反双斜杠”\”
.

\d

\D

\s

\S

\w

\W

\p{name}

\P{name}
除了行终止符之外的所有字符(在DOTALL标志被设置时,则表示所有字符)

一个数字[0-9]

一个非数字[^0-9]

一个空白字符[\t\n\r\f\x0B]

一个非空白字符

一个词语字符[a-zA-Z0-9_]

一个非词语字符

一个命名字符类(字符类的名字见下面)

一个命名字符类的补集
预定义字符类的名字上面预定义字符类\p{name}和\P{name}大括号里面的name
Lower

Upper

Alpha

Digit

Alnum

XDigit

Print或Graph

Punct

ASCII

Cntrl

Blank

Space

javaLowerCase

javaUpperCase

javaWhitespace

javaMirrored

InBlock

IsScript

Category或InCategory

IsProperty
ASCII的小写字母[a-z]

ASCII的大写字母[A-Z]

ASCII的字母[a-zA-Z]

ASCII的数组[0-9]

ASCII的字母或数字[A-Za-z0-9]

十六进制数字[0-9A-Fa-f]

可打印的ASCII字符[\x21-\x7E]

ASCII的非字母和数字字符[\p{Print}&&\P{Alnum}]

所有ASCII字符[\x00-\x7F]

ASCII的控制字符[\x00-\x1F]

空格字符或制表符[\t]

Space[\t\n\r\f\0x0B]

小写字母,正如Character.isLowerCase()确定的字符

大写字母,正如Character.isUpperCase()确定的字符

空白字符,正如Character.isWhitespqce()确定的字符

镜像字符,正如Character.isMirrored()确定的字符

Block是Unicode字符块的名字,不过要剔除名字中的空格,例如Arrows或LatinlSupplement
Script是Unicade脚本的名称,不过要剔除名字中的空格,例如Common

Category是Unicode字符类别的名字,例如,L(字母)和Sc(货币符号)

ProPerty是以下值之一:Alphabetic、Ideographic、Letter、Lowercase、Uppercase、Titlecase、Punctuation、Control、White_Space、Digit、Hex_Digit、Noncharater_Code_Point、Assigned
边界匹配符
^ $输入的开头和结尾(或者在多行模式下行的开头和结尾)
\b一个词语的边界
\B一个非词语的边界
\A输入的开头
\z输入的结尾
Z除了行终止符之外的输入结尾
\G前一个匹配的结尾
量词
X?可选的X
X*X重复0或多次
X+X重复1或多次
X{n} X{n,} X{n,m}X重复n次,至少n次,在n到m次之间
量词后缀
?将默认(贪婪)匹配转为勉强匹配
+将默认(贪婪)匹配转为占有匹配
集合操作
XY任何X中的字符串,后面跟随任何Y中的字符串
X|Y任何X或Y中的字符串
群组
(X)捕获将X作为群组匹配的字符串
\n第n个群组的匹配
转义
\c字符c(必须是不在字母表中的字符)
\Q … \E逐字地引用…
(?…)特殊结构——请查看Pattern类的API注释

3 Java中处理正则表达式

  • java.util.regex.Pattern:模式类,用正则表达式可以构建一个Pattern对象,用来匹配将要输入的字符串。
  • java.util.regex.Matcher:匹配类,调用模式类的matcher(str),向其中输入要匹配的字符串,就可以获得一个Matcher对象。

3.1 基本正则匹配

    Pattern pattern = Pattern.compile(regexString); // 调用Pattern的compile静态方法,输入正则表达式,获得Pattern对象
    Matcher matcher = pattern.matcher(input); // 调用Pattern的mathcer方法,输入要匹配的字符串,获得Matcher对象
    if(matcher.matches()) ...... // 调用Matcher的matches方法来验证字符串是否匹配所给的正则表达式

注意:匹配器的输入可以是任何实现了CharSequence接口的类的对象,例如String、StringBuilder和CharBuffer。

在Pattern类编译这个正则模式时,可以设置一个或多个标志,例如:

        Pattern pattern = Pattern.compile(patternString,
                Pattern.CASE_INSENSITIVE + Pattern.UNICODE_CASE);

下面是所支持的六个标志:

标识描述
CASE_INSENSITIVE匹配字符时忽略字母的大小写,默认情况下,这个标志只考虑US ASCII字符
UNICODE_CASE当与CASE_INSENSITIVE组合时,用Unicode字母的大小写来匹配
MULTILINE^和$匹配行的开头和结尾,而不是整个输入的开头和结尾
UNIX_LINES在多行模式中匹配^和$时,只有’\n’被识别成行终止符
DOTALL当使用这个标志时, . 符号匹配所有符号,包括行终止符
CANON_EQ考虑Unicode字符规范的等价性

3.2 Matcher类的find方法

通常情况下,我们并不会用正则来匹配全部输入,而只是想找出输入中一个或多个匹配的子字符串,这时可以用Matcher类的find来查找匹配内容,如果返回true,再使用start和end方法来查找匹配的内容。

    while(matcher.find()) {
        int start = matcher.start();
        int end = matcher.end();
        String match = input.substring(start, end);
        System.out.println(match);
    }

3.3 替换字符串

使用Matcher类的replaceAll方法可以将正则表达式出现的所有地方都用替换字符来替换,replaceFirst方法将只替换模式的第一次出现,如下:

    Pattern pattern = Pattern.compile("[0-9]+");
    Matcher matcher = pattern.matcher(input);
    String output1 = matcher.replaceAll("#");
    String output2 = matcher.replaceFirst("$");

3.4 分割字符串

Pattern类有一个split方法,类似于String的split方法,可以使用正则表达式来匹配边界进行分割。例如,下面的指令可以将输入分割成标记,其中分割符是由可选的空白字符包围的标点符号。

    Pattern pattern = Pattern.compile("\\s*\\p{Punct}\\s*");
    String[] tokens = pattern.split(input);

3.5 群组

如果正则表达式包含群组,那么Matcher对象可以获得具体的某个群组和揭示群组的边界。

获得某个群组
可以调用Matcher对线的以下方法抽取匹配的字符串中的群组:

String group(int groupIndex)

群组0是整个输入,而用于第一个实际群组的群组索引是1。调用groupCount方法可以获得全部群组的数量。对于嵌套群组来说,是按照前括号进行排序的。

得到群组的边界
Matcher对象以下的方法将产生指定群组的开始索引和结束索引+1,注意加了1所以是结束索引之后的那个索引

int start(int groupIndex)
int end(int endIndex)

例如,假设有下面的正则表达式:

((1?[0-9]):([0-5][0-9]))[ap]m

和下面的输出:

11:59am

那么,11:59am所对应索引是0-6,所包含的群组和边界如下:

群组索引开始结束字符串
00711:59am
10511:59
20211
33559

实例:用括号打印出群组边界

package com.trigl.corejava.regex;

import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
/**
 * 首先提示输入一个模式,然后提示输入用于匹配的字符串,随后将打印出输入是否
 * 与模式相匹配。如果输入匹配模式,并且模式包含群组,那么这个程序将用括号打
 * 印出群组边界
 * 如:
 * (([Cc][Rr][Ee][Aa][Tt][Ee])|([Rr][Ee][Pp][Ll][Aa][Cc][Ee])|(([Cc][Rr][Ee][Aa][Tt][Ee])\s([Oo][Rr])\s([Rr][Ee][Pp][Ll][Aa][Cc][Ee])))\s([Pp][Rr][Oo][Cc][Ee][Dd][Uu][Rr][Ee])
 * 匹配3种类型开头的字符串:create procedure/replace procedure/create or replace procedure
 * @author 白鑫
 * @date 2016年3月16日 上午10:16:27
 */
public class RegexTest {
    public static void main(String[] args) throws PatternSyntaxException {
        // 构造一个新的扫描器,产生来自指定输入流的值,现在是从键盘输入
        Scanner in = new Scanner(System.in);
        System.out.println("Enter Pattern: ");
        // 输入正则表达式并产生模式类对象
        String patternString = in.nextLine();
        Pattern pattern = Pattern.compile(patternString);

        while(true) {
            System.out.println("Enter string to match: ");
            // 输入字符串并尝试匹配类对象
            String input = in.nextLine();
            if(input == null || input.equals("")) return;
            Matcher matcher = pattern.matcher(input);
            // 验证是否匹配,若匹配是否有群组,有的话在群组边界打印括号
            if(matcher.matches()) {
                System.out.println("Match");
                int g = matcher.groupCount();
                if(g > 0) {
                    for (int i = 0; i < input.length(); i++) {
                        // 打印所有的空群组
                        for(int j = 1; j <= g; j++) 
                            if(i == matcher.start(j) && i == matcher.end(j))
                                System.out.print("()");
                        // 打印非空群组的 ( 前半括号
                        for(int j = 1; j <=g; j++)
                            if(i == matcher.start(j) && i != matcher.end(j))
                                System.out.print('(');
                        System.out.print(input.charAt(i));
                        // 打印非空群组的 ) 后半括号
                        for(int j = 1; j <=g; j++)
                            if(i+1 != matcher.start(j) && i+1 == matcher.end(j))
                                System.out.print(')');
                    }
                    System.out.println();
                }
            } else {
                System.out.println("No match");
            }
        }
    }
}

输出结果

Enter Pattern: 
((1?[0-9]):([0-5][0-9]))[ap]m
Enter string to match: 
11:11pm
Match
((11):(11))pm
......

OVER

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值