正则表达式处理

JDK8在线Api中文手册

JDK8在线Api英文手册


   java.util.regex包支持正则表达式处理。作为在此处使用的术语,正则表达式是描述字符序列的一串字符。这种通过描述被称为模式,可以用于在其他字符序列中查找匹配。正则表达式可以指定通配符、一组字符和各种量词。因此,可以指定一种通用形式的正则表达式,以匹配多种不同的特定字符系列。
   正则表达式处理由两个类支持:Pattern和Matcher。这两个类协同工作:使用Pattern类定义正则表达式,使用Matcher类在其他序列中匹配模式。

1 Pattern 类

   Pattern类没有定义构造函数。相反,模式是通过compile()工厂方法创建的。该方法的一种形式如下所示:

static Pattern compile(String pattern)

   其中,pattern是希望使用的正则表达式。compile()方法将pattern中的字符串转换成一种模式,Matcher可以使用这种模式进行模式匹配。该方法返回包含模式的Pattern对象。
   一旦创建Pattern对象,就可以使用Pattern对象创建Matcher对象。这是通过Pattern类定义的matcher()工厂来完成的,该方法如下所示:

Matcher matcher(CharSequence str)

   其中,str是将要用于匹配模式的字符序列,又称为输入序列。CharSequence是接口,定义了一组只读字符。String以及其他类实现了该接口,因此可以向matcher()方法传递字符串。

2 Matcher 类

   Matcher类没有构造函数。相反,正如刚才所解释的,通过调用Pattern定义的matcher()工厂方法来创建Matcher对象。一旦创建Matcher对象,就可以使用Matcher对象的方法来执行各种模式匹配操作。
   最简单的模式匹配方法是matches()。该方法简单地确定字符序列是否与模式匹配,如下所示:

boolean matches()

   如果字符序列与模式相匹配,就返回true;否则返回false。需要理解的是整个序列必须与模式相匹配,而不仅仅是子序列与模式相匹配。
   为了确定输入序列的子序列是否与模式相匹配,需要使用find()方法,该方法的一个版本如下所示:

boolean find()

   如果存在匹配的子序列,就返回true;否则返回false。可以重复调用这个方法,以查找所有匹配的子序列。对find()方法的每次调用,都是从上一次离开的位置开始。
   可以通过调用group()方法来获得包含最后一个匹配序列的字符串,该方法的一种形式如下所示:

String group()

   该方法返回匹配的字符串。如果不存在匹配,就抛出IllegalException异常。
   可以通过调用start()方法,获得输入序列中当前匹配的索引。通过end()方法,可以获得当前匹配序列末尾之后下一个字符的索引。这两个方法如下所示:

int start();
int end();

   如果不存在匹配序列,这两个方法都会抛出IllegalStateException异常。
   可以通过调用replaceAll()方法,使用另一个序列替换所有匹配的序列,该方法入下所示:

String replaceAll(String newStr)

   其中,newStr指定了新的字符序列,该序列将用于替换与模式相匹配的序列。更新后的输入序列作为字符串返回。

3 正则表达式的语法

   一般而言,正则表达式是由常规字符、字符类(一组字符)、通配符以及量词构成的。常规字符根据自身进行匹配。因此,如果模式由"xy"构造而成,那么匹配该模式的唯一输入序列是"xy"。诸如换行符、制表符这类字符,使用标准的转义序列指定,标准转义序列以"“开头。例如,换行符通过”\n"来指定。在正则表达式中,常规字符也被称作字面值。
   字符类是一组字符。通过在方括号之间放置字符,可以指定字符类。例如,类[wxyz]匹配w、x、y、或z。为了指定一组排除性字符,可以在字符前使用"^"。例如,类[^wxyz]匹配除w、x、y以及z之外的字符。可以使用连字符指定字符范围。例如,为了指定匹配数字1到9的字符类,可以使用[1-9]。
   通配符是点(.),可以匹配任意字符。因此,由"."构成的模式将匹配以下(以及其他)输入序列:“A”、“a”、"x"等。
   量词决定表达式将被匹配的次数。量词如下所示:

  • + :匹配一次或多次
  • . :匹配零次或多次
  • ?:匹配零次或一次
       例如,模式"x+“将与"x”、"xx"以及"xxx"等匹配。
       另外一点:一般来说,如果指定的表达式无效,将会抛出PatternSyntaxException异常。

4 演示模式匹配

   要理解正则表达式模式匹配操作的原理,最好的方法是举一些例子。第一个例子如下所示,使用字面值模式查找匹配:

import java.util.regex.Matcher;
import java.util.regex.Pattern;
//A simple pattern matching demo.
class RegExpr {
  public static void main(String[] args) {
      Pattern pat;
      Matcher mat;
      boolean found;
      pat = Pattern.compile("Java");
      mat = pat.matcher("Java");
      found = mat.matches();//check for a match
      System.out.println("Testing Java against Java.");
      if (found) {
          System.out.println("Matches");
      } else {
          System.out.println("No Match");
      }
      System.out.println();
      System.out.println("Testing Java against Java 8.");
      mat = pat.matcher("Java 8");
      found = mat.matches();//check for a match
      if (found) {
          System.out.println("Matches");
      } else {
          System.out.println("No Match");
      }
      /**
       * 输出:
       * Testing Java against Java.
       * Matches
       *
       * Testing Java against Java 8.
       * No Match
       */
  }
}

   下面详细分析这个程序。程序首先创建创建包含序列"Java"的模式。接下来,为该模式创建Matcher对象,该对象具有输入序列"Java"。然后,调用matches()方法来确定输入序列是否与模式匹配。因为输入序列和模式相同,所以matches()方法返回true。接下来,使用输入序列"Java 8"创建新的Matcher对象,并再次调用matches()方法。对于这种情况,模式和输入序列不同,没有发现匹配。请记住,只有当输入序列与模式精确匹配时,matches()方法才返回true;只有子序列匹配时,不会返回true。
   可以使用find()方法来确定输入序列是否包含与模式匹配的子序列。分析下面的程序:

//Use find() to find a subsequence.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class RegExpr2 {
  public static void main(String[] args) {
      Pattern pat = Pattern.compile("Java");
      Matcher mat = pat.matcher("Java 8");
      System.out.println("Looking for Java in Java 8.");
      if(mat.find()){
          System.out.println("subsequence found");
      }else{
          System.out.println("No Match");
      }
  }
  /**
   * 输出:
   * Looking for Java in Java 8.
   * subsequence found
   */
}

   在这个例子中,find()方法找到了子序列"Java"。
   可以使用find()方法查找输入序列中模式重复出现的次数,因为每次find()调用,都是从上一次离开的地方开始查找。例如,下面的程序可以找出与模式"test"的两次匹配。

//Use find() to find multiple subsequence.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class RegExpr3 {
  public static void main(String[] args) {
      Pattern pat = Pattern.compile("test");
      Matcher mat = pat.matcher("test 1 2 3 test");
      while ((mat.find())){
          System.out.println("test found at index "+mat.start());
      }
  }
  /**
   * 输出:
   * test found at index 0
   * test found at index 11
   */
}

   正如输出所显示的,找到了两个匹配。程序使用start()方法获取每个匹配的索引。
   1. 使用通配符与量词
   尽管前面的程序显示了使用Pattern和Matcher类的通用技术,但是这些程序没有展示出它们的强大功能。只有在用到通配符和量词时,才能真正发现正则表达式处理带来的好处。该例使用量词"+"来匹配任意长度的"W"序列。

//Use a quantifier.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class RegExpr4 {
  public static void main(String[] args) {
      Pattern pat = Pattern.compile("W+");
      Matcher mat = pat.matcher("W WW WWW");
      while (mat.find()){
          System.out.println("Match: "+mat.group());
      }
  }
  /*
  输出:
  Match: W
  Match: WW
  Match: WWW
   */
}

   正如输出所显示的,正则表达式模式"W+“能匹配任意长度的W序列。
   下一个程序使用通配符创建了一个模式,该模式将匹配以e开始并以d结束的任意序列。为了达到这一目的,使用点通配符和”+";量词:

//Use wildcard and quantifier.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class RegExpr5 {
 public static void main(String[] args) {
     Pattern pat = Pattern.compile("e.+d");
     Matcher mat = pat.matcher("extend cup end table");
     while ((mat.find())){
         System.out.println("Match: "+mat.group());
     }
 }
 /*
 Match: extend cup end
  */
}

   只发现一个匹配,并且是以e开头、以d结尾的最长序列。我们可能会期望得到两个匹配:“extend"和"end”。发现更长序列的原因是,默认情况下,find()方法会匹配适合模式的最长序列,这被称为"贪婪行为"。可以通过为模式添加"?“量词来指定"胁迫行为”,如下面的版本所示,这将导致获得最短的匹配模式:

//Use the ? quantifier.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class RegExpr6 {
  public static void main(String[] args) {
      //Use reluctant matching behavior.
      Pattern pat = Pattern.compile("e.+?d");
      Matcher mat = pat.matcher("extend cup end table");
      while ((mat.find())) {
          System.out.println("Match: " + mat.group());
      }
  }
    /*
  Match: extend
  Match: end
   */
}

   正如输出所显示的,模式"e.+?d"将会匹配以e开始并且以d结尾的最短序列。因此,找到了两个匹配。
   2. 使用字符类
   有时会希望以任意顺序包含一个或多个字符的任意序列。例如,为了匹配整个单词,希望匹配字母表的任意序列。实现这一目的的最简单方法是使用字符类。字符类定义了一组字符。字符类是通过在方括号中放置希望匹配的字符来创建的。例如,为了匹配从a到z的小写字母,可以使用[a-z]。下面的程序演示了这种技术:

//Use a character class.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class RegExpr7 {
  public static void main(String[] args) {
      //Match lowercase words.
      Pattern pat = Pattern.compile("[a-z]+");
      Matcher mat = pat.matcher("this is a test.");
      while ((mat.find())){
          System.out.println("Match: "+mat.group());
      }
  }
  /*
  输出:
  Match: this
  Match: is
  Match: a
  Match: test
   */
}

   3. 使用replaceAll()方法
   Matcher类提供的replaceAll()方法用于使用正则表达式执行强大的搜索和替换操作。例如,下面的程序使用"Eric"替换所有以"Jon"开头的序列:

//Use replaceAll()
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class RegExpr8 {
  public static void main(String[] args) {
      String str="John Jonathan Frank Ken Todd";
      Pattern pat = Pattern.compile("Jon.*? ");
      Matcher mat =pat.matcher(str);
      System.out.println("Original sequence: "+str);
      str= mat.replaceAll("Eric ");
      System.out.println("Modified sequence: "+str);
  }
  /*
  输出:
  Original sequence: John Jonathan Frank Ken Todd
  Modified sequence: John Eric Frank Ken Todd
   */
}

   因为正则表达式"Jon.*? "匹配以Jon开头、后面跟随零个或多个字符并以空格结尾的任意字符串,所以可以用于匹配Jon和Jonathan,并使用Eric替换它们。如果不使用模式匹配功能,这种替换很难实现。
   4. 使用split()方法
   使用Pattern类定义的split()方法,可以将输入序列化简化成单个标记。split()方法的一种形式如下所示:

String[] split(CharSequence str)

该方法处理str传入的输入序列,根据模式指定的定界符将输入序列简化成标记:

//Use split().
import java.util.regex.Pattern;
class RegExpr9 {
  public static void main(String[] args) {
      //Match lowercase words.
      Pattern pat = Pattern.compile("[ ,.!]");
      String strs[] = pat.split("one two,alpha9 12!done.");
      for (int i=0;i<strs.length;i++){
          System.out.println("Next token: "+strs[i]);
      }
  }
  /*
  输出:
  Next token: one
  Next token: two
  Next token: alpha9
  Next token: 12
  Next token: done
   */
}

   正如输出所显示的,这个输入序列被简化成单个编辑。注意不包含定界符。

5 模式匹配的两个选项

   尽管前面描述的模式匹配技术提供了最强大的灵活性和功能,但是还有另外两种技术在某些环境下可能会有用。如果只需要进行一次模式匹配,可以使用Pattern类定义的matches()方法。该方法如下所示:

static boolean matches(String pattern,CharSequence str)

   如果pattern与str匹配,就返回true;否则返回false。这个方法自动编译pattern,然后查找匹配。如果需要重复使用相同的模式,那么相对于前面模式的先编译模式、后使用Matcher类定义的方法进行匹配,使用matches()方法的效率更低。
   也可以使用String类实现的matches()方法执行模式匹配,该方法如下所示:

boolean matches(String pattern)

   如果调用字符串与pattern中的正则表达式相匹配,matches()方法就返回true,否则返回false。

发布了59 篇原创文章 · 获赞 20 · 访问量 3626

猜你喜欢

转载自blog.csdn.net/qq_34896730/article/details/105011651