首页 > 技术文章 > 正则表达式对象的创建与使用

guohaien 2017-08-01 11:04 原文

字符串对象


 

使用正则表达式最简单的办法,就是直接调用字符串对象的方法。

  • matches : 检查是否匹配上指定的正则表达式
    System.out.println("1234".matches("\\d+")); // true
  • split : 将字符串从指定的正则表达式匹配的位置拆分,另外还有一个重载的方法可以指定拆分成多少个
    String str = "Hello world 47";
    String[] arr = str.split(" ");
    System.out.println(Arrays.toString(arr)); // [Hello, world, 47]
    arr = str.split(" ", 2);
    System.out.println(Arrays.toString(arr)); // [Hello, world 47]
  • replaceFirst、replaceAll : 替换第一个、全部匹配上指定正则表达式的子串

    String str = "Hello world 47";
    System.out.println(str.replaceFirst("\\d", "*")); // Hello world *7
    System.out.println(str.replaceAll("\\d", "*")); // Hello world **

Pattern和Matcher对象的创建


由于String类的功能有限,所以我们经常需要构建功能强大的正则表达式对象。通过Pattern.compile()方法来根据传入的String类型的正则表达式生成Pattern对象,然后把需要检索的字符串传入Pattern类的matcher方法生成Matcher对象,Matcher中提供了大量的方法满足我们的需求。Matcher对象的创建过程如下

Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher("123456");

 其中Pattern还提供了一个重载的compile方法,第二个参数为标记参数(可以传入多个用"|"连接),这些标记都是Pattern类中的常量。如下

  • Pattern.CANON_EQ:当且仅当两个字符的完全规范分解都相同的情况下,才认定匹配。比如用了这个标志之后,表达式"a/u030A"会匹配"\u00E5"(默认不匹配)
  • Pattern.CASE_INSENSITIVE(?i)、Pattern.UNICODEC_CASE(?u):两个结合使用可以无视大小写(默认只有US-ASUII字符集是可以)
  • Pattern.COMMENTS(?x):空格与#开头的行到行末会被忽略
  • Pattern.DOTALL(?s):"."可以匹配所有字符包括换行符(默认不包括)
  • Pattern.MULTILNE(?m):多行情况下"^"和"$"分别匹配一行的开始与结尾(默认是整个字符串的开始与结尾)
  • Pattern.UNIX_LINES(?d):"."、"^"和"&"只识别换行符"\n"

以上标记参数后面的括号内的字符若直接插入在正则表达中,将拥有与传入标记参数一样的效果。如下所示

Pattern p = Pattern.compile("^java", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
//Pattern p = Pattern.compile("(?i)(?m)^java");
Matcher m = p.matcher("java is good\nJAVA is best");
while (m.find())
    System.out.print(m.group() + " "); // java JAVA

上面代码中用到Matcher对象的find与group方法将在下面进行讲解。可以看出以上两种创建Pattern对象的方式,将不会影响最后的输出结果。而且由于传入了标记参数所以可以无视大小写成功匹配JAVA并且字符串中含有换行符所以匹配到了两个结果

Matcher对象的方法以及使用


  • matches:判断整个字符串是否都匹配正则表达式
  • lookingAt:从字符串的开头判断是否匹配正则表达式但可以不用整个都匹配
  • find:像迭代器那样向前遍历字符串,查找是否有匹配字符串片段。该方法还有一个重载的方法,可以传入一个索引值,即从该索引位置起查找是否有匹配的
  • group:当没有参数时返回前一次匹配成功的字符串(匹配整个正则表达式),由于一个正则表达式可以有包含多个括号,即拥有多个组,所以该方法可以传入一个数字,来返回匹配上某个组的字符串,当传入的数字为0时与未传参一样
  • groupCount:返回该正则表达式总共有可以分成多少组
    String s = "Hello world, my name is ghaien.\n" +
            "this is a demo from a book.\n" +
            "it's named thinking in java.";
    Matcher m = Pattern.compile("(?m)((\\S+)\\s+(\\S+))$").matcher(s);
    while (m.find()) {
        for (int i = 0; i < m.groupCount(); i++)
            System.out.print("[" + m.group(i) + "]");
        System.out.println();
    }/* output
        [is ghaien.][is ghaien.][is]
        [a book.][a book.][a]
        [in java.][in java.][in]
    */
  • start:返回先前匹配上的字符串的起始位置的索引值
  • end:返回先前匹配上的字符串的最后位置的索引值加一
  • replaceFirst、replaceAll:将匹配上的字符串的第一个、所有替换成指定的字符串
  • appendReplacement:这个方法会对字符串进行渐进式的替换,并将替换后的字符串通过指定的StringBuffer对象拼接起来
  • appendTail:通常用来结合上一个方法来使用,当替换了多次之后可以调用这个方法将后面没有被替换的字符串复制到StringBuffer中
    String s = "Hello world 47";
    Matcher m = Pattern.compile("[a-zA-Z]").matcher(s);
    System.out.println(m.replaceFirst("*"));
    m = Pattern.compile("[a-zA-Z]").matcher(s);
    System.out.println(m.replaceAll("*"));
    m = Pattern.compile("[a-zA-Z]").matcher(s);
    StringBuffer sb = new StringBuffer();
    int i = 0;
    while (m.find())
        m.appendReplacement(sb, i++ + "");
    System.out.println(sb);
    m.appendTail(sb);
    System.out.println(sb);
    /* output
        *ello world 47
        ***** ***** 47
        01234 56789
        01234 56789 47
     */

    从上面的代码中可以看出replaceFirst与replaceAll只能将一个或所有匹配的替换成某个指定的字符串,这有时候并不能满足我们的需求,而appendReplacement方法的替换是渐进式的并且每次都能替换成我们所需要的,从后面来两个输出的结果也能够很直接的看出appendTail方法的作用

  • reset:可以将现有的Matcher对象应用于一个新的字符串

 

推荐阅读