码迷,mamicode.com
首页 > 编程语言 > 详细

Java基础——字符串正则及Scanner

时间:2015-02-26 11:12:36      阅读:243      评论:0      收藏:0      [点我收藏+]

标签:

1、正则表达式

1.1、基础
字符串处理问题一般集中在匹配、选择、编辑于验证上,而正则表达式提供了一种完全通用的方式来解决这些问题
正则表达式就是以某种模式描述字符串,因此你可以说:“如果一个字符串含有这些东西,那么它就是我要找的东西”。例如我们可以用一下模式匹配数字:(-|\\+)?\\d+,他可以匹配任意整数。
测试如下:
public class IntegerMatch {
     public static void main(String[] args) {
           System. out.println("-1234" .matches("(-|\\+)?\\d+"));
           System. out.println("1234" .matches("(-|\\+)?\\d+"));
           System. out.println("+1234" .matches("(-|\\+)?\\d+"));
           System. out.println("s1234d" .matches("(-|\\+)?\\d+"));
           System. out.println("test" .matches("(-|\\+)?\\d+"));
     }
}
      输出:true,true,true,false,false,符合预期。
      分析我们编写的正则表达式,(-|\\+)表示-号或者+号,中间的|表示或,\\+表示+号,由于“+”是正则表达式的特殊字符,所以需要用\\进行转义。
 
1.2、创建正则表达式
在JDK文档的java.util.regex包下的Pattern类有对正则表达式的构造规则进行了详细描述,在这里描述的是里面比较重要的一些规则。
1.2.1字符
Java正则表达式创建字符的方式有:
       字符
B 指定字符B
\xhh 表示16进制为oxhh的字符
\uhhhh 16进制表示为0xhhhh的Unicode字符
\t 制表符
\n 换行符
\r 回车
\f 换页
\e 转义,Escape
 
1.2.2字符类
Java正则表达式支持的字符类有:
                  字符类
. 任何字符
[abc] a、b 或 c(简单类)
[^abc] 任何字符,除了 a、b 或 c(否定)
[a-zA-Z] a 到 z 或 A 到 Z,两头的字母包括在内(范围)
[a-d[m-p]] a 到 d 或 m 到 p:[a-dm-p](并集)
[a-z&&[def]] d、e 或 f(交集)
[a-z&&[^bc]] a 到 z,除了 b 和 c:[ad-z](减去)
\D 非数字: [^0-9]
\s 空白字符:[ \t\n\x0B\f\r]
\S 非空白字符:[^\s]
\w 单词字符:[a-zA-Z0-9]
\W 非单词字符:[^\w]
1.2.3 逻辑操作符
逻辑操作符
XY Y跟在X后面
X|Y X或Y
(X) 捕获组,可以在表达式中用\i引用第i个捕获组
 
1.2.4 边界匹配符
边界匹配符
^ 行的开头
$ 行的结尾
\b 单词边界
\B 非单词边界
\G 上一个匹配的结尾
 
      作为例子,下面每一个正则表达式都能成功匹配字符序列“Rudolph”
public class Rudolph {
     public static void main(String [] args) {
            for(String pattern : new String[]{ "Rudolph",
                      "[rR]udolph", "[rR][aeiou][a-z]ol.*" , "R.*" })
                      System.out.println("Rudolph" .matches(pattern));
     }
}
 
1.3、量词
      量词描述了一个模式吸收输入文本的方式,Java有三种量词模型:贪婪型,勉强型以及占有型。贪婪型会为所有可能的模式大仙尽可能多的匹配,是Java的默认量词模型;勉强型,用问号表示,匹配满足模式所需的最少字符;占有型是Java特有的,可以防止正则表达式失控,使正则表达式执行更有效。
贪婪型 勉强型 占有型 如何匹配
X? X?? X?+ 一个或零个X
X* X*? X*+ 零个或多个X
X+ X+? X++ 一个或多个X
X{n} X{n}? X{n}+ 恰好n次X
X{n,} X{n,}? X{n,}+ 至少n次X
X{n,m} X{n,m}? X{n,m}+ X至少n次,且不超过m次
 
1.4、Pattern和Matcher
      可以使用static Pattern.compile()来编译正则表达式,它会生成一个Pattern对象,然后把你想要检索的字符串传入Pattern对象的matcher()方法,matcher()方法会生成一个Matcher对象,它有很多功能可以使用。下面是一个使用Pattern类和Matcher类的例子。
import java.util.regex.*;
 
public class TestRegularExpression {
     public static void main(String[] args) {
           String testString = "abcabcabcdefabc";
           String[] patterns = { "abcabcabcdefabc", "abc+" , "(abc)+", "(abc){2,}" };
           
            for (String pattern : patterns) {
                System. out.println("Regular expression: \"" + pattern + "\"" );
                 Pattern p = Pattern .compile(pattern);
                Matcher m = p.matcher(testString);
                 while (m.find()) {
                     System. out.println("Match \"" + m.group() + "\" at positions " + m.start()
                                + "-" + (m.end() - 1));
                }
           }
     }
}
      首先根据正则构造Pattern,然后调用Pattern上的matcher()方法得到Matcher对象,接下来就是调用Matcher类上的方法进行操作:find()方法会尝试查找与该模式匹配的输入序列的下一个子序列。此方法从匹配器区域的开头开始,如果该方法的前一次调用成功了并且从那时开始匹配器没有被重置,则从以前匹配操作没有匹配的第一个字符开始。如果匹配成功,则可以通过 startendgroup 方法获取更多信息。group()方法返回由以前匹配操作所匹配的输入子序列。start()方法返回先前匹配序列的起始位置索引。end()方法返回所匹配的最后字符的索引加1的值。
 
      下面的例子会将字符串划分为一个一个单词,并把单词输出:
import java.util.regex.*;
 
public class Finding {
  public static void main(String[] args) {
    Matcher m = Pattern.compile("(\\w|‘)+" )
      .matcher( "Evening is full of the linnet‘s wings" );
    while(m.find())
      System. out.println(m.group() + " " );
    System.out.println();
  }
}
 
1.5 组:
      组是用括号划分的正则表达式,可以根据组的编号来引用某个组,组号为0表示整个表达式,组号1表示被第一对括号括起来的组,例如A(B(C))D有三个组,组0是ABCD,组1是BC,组2是C。
import java.util.regex.*;
 
public class Groups {
     static public final String POEM = "Twas brillig, and the slithy toves\n"
                + "Did gyre and gimble in the wabe.\n"
                + "All mimsy were the borogoves,\n"
                + "And the mome raths outgrabe.\n\n"
                + "Beware the Jabberwock, my son,\n"
                + "The jaws that bite, the claws that catch.\n"
                + "Beware the Jubjub bird, and shun\n"
                + "The frumious Bandersnatch." ;
 
     public static void main(String[] args) {
           Matcher m = Pattern.compile("(?m)(\\S+)\\s+((\\S+)\\s+(\\S+))$")
                     .matcher( POEM);
            while (m.find()) {
                 for (int j = 0; j <= m.groupCount(); j++)//注意,这里是小于等于
                     System. out.println("[" + m.group(j ) + "]");
                System. out.println();
           }
     }
}
      POEM是一个多行字符串,正则表达式的(?m)表示启用多行模式,\\S+匹配一个或多个非空白符,\\s+匹配一个或多个空白符。groupCount()返回该匹配器模式中的分组数目,第0组不包括在内,group()返回前一次匹配操作的第0组,group(int i)返回前一次匹配操作指定的组号,start(int group)返回指定组的起始索引,end(int group)返回指定组的最后一个字符索引+1的值。
 
      Matcher类还有两个很重要的方法:matches()以及lookingAt()方法。matches()尝试将整个区域与模式匹配。如果匹配成功,则可以通过 startendgroup 方法获取更多信息。 lookingAt()方法将从区域开头开始的输入序列与该模式匹配。 与matches()方法不同的是,它不需要匹配整个区域。 如果匹配成功,则可以通过 startendgroup 方法获取更多信息。
 
1.6 
      Pattern类的compile()还有另外一个版本,它接受一个标记参数,以调整匹配的行为:Pattern Pattern.compile(String regex, int flag),Java定义的flag有:1、Pattern.UNIX_LINES(?d)表示启用Unix行模式;2、Pattern.CASE_INSENSITIVE(?i)启用不区分大小写的匹配;3、Pattern.COMMENTS(?x)允许空白和注释;4、Pattern.MULTILINE(?m)启用多行模式;5、Pattern.LITERAL启用模式的字面值解析;6、Pattern.DOTALL(?s)启用dotall模式;7、Pattern.UNICODE_CASE(?u)启用Unicode感知的大小写折叠;8、Pattern.CANON_EQ:启用规范等价。
 
     其中比较有用的是Pattern.CASE_INSENSITIVE(?i),Pattern.MULTILINE(?m),Pattern.COMMENTS(?x)。
import java.util.regex.*;
 
public class ReFlags {
     public static void main(String[] args) {
           Pattern p = Pattern. compile("^java", Pattern.CASE_INSENSITIVE
                     | Pattern. MULTILINE);
           Matcher m = p.matcher( "java has regex\nJava has regex\n"
                     + "JAVA has pretty good regular expressions\n"
                     + "Regular expressions are in Java" );
            while (m.find())
                System. out.println(m.group());
     }
}
      输出:java    Java    JAVA
 
1.7 
      split()方法用于断开字符串,一共有两个版本的split()方法,split(CharSequence input)以及split(CharSequence input, int limit),这里的limit限定模式只能使用limit-1次。
直接看例子:
import java.util.regex.*;
import java.util.*;
 
public class SplitDemo {
     public static void main(String[] args) {
           String input = "This!!unusual use!!of exclamation!!points";
          System. out.println(Arrays.toString(Pattern. compile("!!").split(input)));
          System. out.println(Arrays.toString(Pattern. compile("!!")
                     .split(input, 3)));
          System. out.println(Arrays.toString(Pattern. compile("~~").split(input)));
     }
}
      输出:
[This, unusual use, of exclamation, points]
[This, unusual use, of exclamation!!points]
[This!!unusual use!!of exclamation!!points]
      当找不到模式时,会输出整个字符串。
 
1.8 替换操作
      常用的替换操作有replaceFirst(),replaceAll()以及appendReplacement()。以下的例子展示了replaceFirst()与replaceAll()的用法。
import java.util.regex.*;
 
public class TheReplacements {
     public static void main(String[] args) throws Exception {
           String s = "/*! Here‘s a block of text to use as input to\n"
                     + "the regular expression matcher. Note that we‘ll\n"
                     + "first extract the block of text by looking for\n"
                     + "the special delimiters, then process the\n"
                     + "extracted block. !*/";
           Matcher mInput = Pattern. compile("/\\*!(.*)!\\*/", Pattern.DOTALL)
                     .matcher(s); // 匹配/*! !*/的正则表达式
            if (mInput.find()) {
                s = mInput.group(1);
           }
 
           s = s.replaceAll( " {2,}", " " ); // 把多个空格替换为一个
           s = s.replaceAll( "(?m)^ +", "" ); // 把行首的空格去掉,注意,要打开多行模式
           System. out.println(s);
 
           s = s.replaceFirst( "[aeiou]", "(VOWEL1)" );
     }
}
      appendReplacement()与另外两个方法不同,他是渐进式的替换,它允许你在替换的过程中操作用来替换的字符串,下面是一个使用appendReplacement()的例子:
import java.util.regex.*;
 
public class TheReplacements {
     public static void main(String[] args) throws Exception {
           Pattern p = Pattern. compile("cat");
           Matcher m = p.matcher( "one cat two cats in the yard");
           StringBuffer sb = new StringBuffer();
            while (m.find()) {
                m.appendReplacement(sb, m.group().toUpperCase());
           }
           m.appendTail(sb);
           System. out.println(sb.toString());
     }
}
      输出:one CAT two CATs in the yard
      一般来说,你应该遍历执行所有的替换操作,然后再调用appendTail()方法,但是如果你想模拟replaceFirst()的行为,那你只需执行一次替换即可。
 
1.9 reset()方法可以将现有的Matcher对象应用于一个新的字符序列:
import java.util.regex.*;
 
public class Resetting {
     public static void main(String[] args) throws Exception {
           Matcher m = Pattern.compile("[frb][aiu][gx]").matcher( "fix the rug with bags");
            while (m.find())
                System. out.print(m.group() + " " );
           System. out.println();
           m.reset( "fix the rig with rags");               //reset方法
            while (m.find())
                System. out.print(m.group() + " " );
     }
}
 
2、Scanner工具类
2.1、扫描输入
import java.io.BufferedReader;
import java.io.StringReader;
import java.util.Scanner;
 
public class BetterRead {
     public static void main(String[] args) {
           Scanner stdin = new Scanner(new BufferedReader(new StringReader(
                      "Sir Robin of Camelot\n22 1.61803" )));
           System. out.println("What is your name?" );
           String name = stdin.nextLine();                               //读取一行
           System. out.println(name);
           System. out.println("How old are you? What is your favorite double?");
           System. out.println("(input: <age> <double>)" );
            int age = stdin.nextInt();                                    //读取整数
            double favorite = stdin.nextDouble();           //读取浮点数
           System. out.println(age);
           System. out.println(favorite);
           System. out.format("Hi %s.\n" , name);
           System. out.format("In 5 years you will be %d.\n" , age + 5);
           System. out.format("My favorite double is %f." , favorite / 2);
     }
} 
 
2.2、Scanner定界符
      默认情况Scanner使用空白符对输入进行分词,但是你也可以使用正则表达式指定自己所需的定界符:
import java.util.*;
 
public class ScannerDelimiter {
  public static void main(String[] args) {
    Scanner scanner = new Scanner("12, 42, 78, 99, 42");
    scanner .useDelimiter("\\s*,\\s*" );
    while(scanner .hasNextInt())            //读取整数
      System. out.println(scanner.nextInt());
  }
}
      这个例子使用逗号作为定界符,输出12   42  78  99  42
 
2.3、用正则表达式扫描
      除了能够扫描基本类型之外,你还能够使用自定义的正则表达式进行扫描:
import java.util.regex.*;
import java.util.*;
 
public class ThreatAnalyzer {
     static String threatData = "58.27.82.161@02/10/2005\n" +
                 "204.45.234.40@02/11/2005\n" +
                 "58.27.82.161@02/11/2005\n" +
                 "58.27.82.161@02/12/2005\n" +
                 "58.27.82.161@02/12/2005\n" +
                 "[Next log section with different data format]" ;
     
     public static void main(String[] args) {
           Scanner scanner = new Scanner(threatData);
           String pattern = "(\\d+[.]\\d+[.]\\d+[.]\\d+)@" + "(\\d{2}/\\d{2}/\\d{4})" ;
  
            while(scanner.hasNext(pattern)) {
                scanner.next(pattern);
                MatchResult match = scanner.match();
                String ip = match.group(1);
                String date = match.group(2);
                System. out.format("Threat on %s from %s\n" , date,ip);
           }
     }
}

Java基础——字符串正则及Scanner

标签:

原文地址:http://www.cnblogs.com/timlearn/p/4300639.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!