现在的位置: 首页 > 综合 > 正文

正则表达式在Java中的应用 .

2013年03月19日 ⁄ 综合 ⁄ 共 10536字 ⁄ 字号 评论关闭
 

自己对正则表达式认识不深,但经常会用到。所以将常用的正则稍微进行整理整理。

 

    

1.什么是正则表达式?
正则表达式就是使用某种模式匹配字符串的公式。
可以说任何的编程语言都提供的机制。
2.正则表达式使用的场合
•表单验证:如长度验证,邮件格式验证等等。
•字符串处理:如匹某条数据的某段信息,将字符串进行分割,替换等操作。
3.正则表达式的构成
正则表达式有一些普通字符和一些元字符组成。普通字符包括大小写的字符和数字。
元字符包括以下几种:
 
/** .元字符的使用 */
public static void RegexMethodOne() {
        String[] arrays = {"rat", "rut", "r t", "root", "remst" };
        String regex = "r.t";
        for (String str : arrays) {
            System.out.println(str + "------->" + str.matches(regex));
        }
    }
$  :匹配行结束的标记。
*  :匹配O个或者多个在它之前的那个字符。
/** $,*元字符的使用 */
 public static void RegexMethodTwo() {
        String[] arrays = {"I love you", "I love you." };
        String regex = "^I.*you$";
        for (String str : arrays) {
            System.out.println(str + "------->" + str.matches(regex));
        }
    }
^  :匹配一行的开始。
*  :匹配O个或者多个在它之前的那个字符。
 
/** ^,*元字符的使用 */
public static void RegexMethodThree() {
        String[] arrays = {"where are you going", "what are you doing" };
        String regex = "^where.*";
        for (String str : arrays) {
            System.out.println(str + "------->" + str.matches(regex));
        }
    }
[] :匹配括号中的任意一个字符。例如:例如正则表达式[0-9]可以匹配任何数字字符;例如正则表达式[A-Za-z]可以匹配任何大小写字母。[]元字符还有一个重要的用法就是“排除”。例如正则表达式[^wubq] 可以匹配除了w,u,b,q字母之外的任何字符。
/** []元字符的使用 */
public static void RegexMethodFour() {
        String[] arrays = {"A,is a character", "B,is a character", "C,is a character" };
        String regex = "^[AB],is a character$";
        for (String str : arrays) {
            System.out.println(str + "------->" + str.matches(regex));
        }
    }
 
() :将(和)之间的表达式定义为“组”。组的含义类似于数学中的小括号,括号内部的运算是一个整体。
/** ()元字符的使用 */
 public static void RegexMethodFive() {
        String str = "{loginname=wubaoquan,loginpassword=1987521,usersex=man,userage=23}";
        String regex = "=([a-z0-9]+)";
        Pattern pattern = Pattern.compile(regex);
        Matcher m = pattern.matcher(str);
        while (m.find()) {
System.out.println(m.group(1));
}
    }
+  :匹配1或多个正好在它之前的那个字符。
 
/** +元字符的使用 */
    public static void RegexMethodSix() {
        String[] arrays = {"8", "88", "888", "8a", "89" };
        String regex = "8+";
        for (String str : arrays) {
            System.out.println(str + "------->" + str.matches(regex));
        }
    }
?  :匹配0或1个正好在它之前的那个字符。
/** ?元字符的使用 */
    public static void RegexMethodEight() {
        String str = "</input><p>12312312312</br><a>b.jsp</a>";
        String regex = "</?[a-z]+>";
        Pattern pattern = Pattern.compile(regex);
        Matcher m = pattern.matcher(str);
        while (m.find()) {
            System.out.println(m.group());
        }
    }
 
{} :匹配指定数目的字符。{}元字符以下几种用法:
{i}   :匹配指定i个字符。
{i,} :匹配指定大于等于i个字符。
{i,j}:匹配指定i到j个字符。
/** {}元字符的使用 */
    public static void RegexMethodSeven() {
        String[] arrays = {"cc", "aaaaa", "000000", "bbbbbbb", "dddddddd", "111111111" };
        String regex = "[0-9a-z]{5,8}";
        // String regex = "[0-9a-z]{5,}";
        // String regex = "[0-9a-z]{5}";
        for (String str : arrays) {
            System.out.println(str + "------->" + str.matches(regex));
        }
    }
 
其他一些常用的元字符:
|  匹配或。如A|B,能够匹配A或者是B
/w 匹配字母或数字或下划线或汉字
/s 匹配任意的空白符
/d 匹配数字
/b 匹配单词的开始或结束
 
正则表达式在Java中使用形式
1.String.split(“正则表达式”);返回一个字符串数组。
 /** String.split(regexStr) */
    public static void RegexTypeOne(){
        String str="txt.jpg,csv|xls";
        String[] array=str.split("[.,|]");
        for(String string:array){
            System.out.println(string);
        }
    }
2.String.split(“正则表达式”,int limit);返回一个字符串数组。limit 参数控制模式应用的次数,因此影响结果数组的长度。如果该限制 n 大于 0,则模式将被最多应用 n - 1 次,数组的长度将不会大于 n。如果 n 为非正,则模式将被应用尽可能多的次数,而且数组可以是任意长度。如果 n 为零,则模式将被应用尽可能多的次数,数组可有任何长度。
 
/** String.split(regexStr,limit) */
    public static void RegexTypeTwo(){
        String str="15*(8+36*11)";
        String[] array=str.split("//*",2);
        for(String string:array){
            System.out.println(string);
        }
    }
3.String.matches(“正则表达式”) ;返回true或者false.
 /** String.matches(regex)  */
    public static void RegexTypeThree(){
        String[] array={"123","123a","@123","444"};
        for(String str : array){
            System.out.println(str+"-------->"+str.matches("//d+"));
 
4.String.replaceAll (“正则表达式”,“替换后的字符串”);返回进行替换后的新字符串。
 /** String.replaceAll(regex, replacement) */
    public static void RegexTypeFour(){
        String str="<p>we will replace of html mark</p>";
        System.out.println(str.replaceAll("</?p>",""));
    }
5.Pattern、Matcher模式匹配。
Pattern就是正则表达式的编译表示形式。也可理解为模式。
Pattern p = Pattern.compile(“正则表达式”);
Matcher m = p.matcher(“字符序列");
 
实例2:从一个字符串中选出邮件地址的格式正确的子串。
 /** Pattern Matcher */
    public static void RegexTypeSix() {
        String str="$$$$wubq@xxxxx.cn";
        Pattern pattern=Pattern.compile("//w+([-+.]//w+)*@//w+([-.]//w+)*//.//w+([-.]//w+)*");
        Matcher m=pattern.matcher(str);
        if (m.find()){
        //如果匹配成功,通过m.group()可以获取匹配到的字符串
            System.out.println(str+"------>"+m.group());
//如果匹配成功,通过m.start()可以获取匹配子串的开始位置
            System.out.println(str+“------>”+m.start());
//如果匹配成功,通过m.end()可以获取匹配子串的结束位置
            System.out.println(str+"------>"+m.end());
        }
    }
 
实例3:从一串数字中挑选出所有以135,136,158,159开头的手机号。
 
/** Pattern Matcher */
    public static void RegexTypeSeven() {
        String str="786313521102915898884821362123456777136234515921117511";
        Pattern pattern=Pattern.compile("(135|136|158|159)[0-9]{8}");
        Matcher m=pattern.matcher(str);
        while(m.find()){
            System.out.println(str+"------>"+m.group());
        }
    }
在上述一串数字的字符串中,存在符合条件的手机号码有:
13521102915,15898884821,13621234567
13623451592,15921117511
而我们执行程序后发现,只得到以下三个手机号:
13521102915,13621234567,13623451592
我们猜想是我们的正则表达式写错了吗?
(135|136|158|159)[0-9]{8},去匹配135或者136或者158或者159的数字,后面在跟上8位数字,没有错呀。呵呵,确实没有错,玄机其实在find方法中。
 
实例4:改进刚才的实例3,选出正确的手机号码。
 
/** Pattern Matcher */
    public static void RegexTypeEight() {
        String str="786313521102915898884821362123456777136234515921117511";
        Pattern pattern=Pattern.compile("(135|136|158|159)[0-9]{8}");
        Matcher m=pattern.matcher(str);
//记录匹配的起点
        int step=0;
        while(m.find(step)){
            System.out.println(m.group());
//当匹配成功后,将下次匹配的位置向后移动三位。
          step=m.start()+3;
        }
    }
再次运行后,我们得到了正确的结果:
13521102915,15898884821,13621234567
13623451592,15921117511
原来find()方法,从匹配器区域的开头开始,如果该方法的前一次调用成功了并且从那时开始匹配器没有被重置,则从以前匹配操作没有匹配的第一个字符开始。
 
实例5:忽略大小写匹配。
 
 /** Pattern Matcher */
    public static void RegexTypeNine() {
        String str ="Book";
        Pattern pattern = Pattern.compile("book");
        //Pattern pattern =Pattern.compile("book",Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(str);
        System.out.println(str+"------->"+matcher.matches());
    }
上面的这个表达式 book 是不能匹配字符串 Book 的,这时我们只要给定编译时的参数就可以了:
Pattern pattern = Pattern.compile(“book”, Pattern.CASE_INSENSITIVE);
Pattern.CASE_INSENSITIVE 这是一个 int 类型的常量,值为 2。表示表达式忽略大小写进行区配。如果我们不采用 Pattern 和 Matcher 两个类来匹配的话,只是使用 String 的 matches 方法的话,我们就不能指定表达式的编译参数了,这时就需要采用内嵌标志表达式了。 
 
实例6:内嵌标志表达式。
 
/** Pattern Matcher */
    public static void RegexTypeTen() {
        String str = "Book";
        String regex = "(?i)book";
        System.out.println(str+"------->"+str.matches(regex));
    }
与 Pattern.CASE_INSENSITIVE 对应的内嵌标志表达式是 (?i),它有四种形式:
1:(?i)
2:(?-i)
3:(?i:X)
4:(?-i:X)
不带有 - 的是开标志,带有 - 的是关标志。我们就达到了同样的效果,当然这样并不是最好的,因为字符串中只有B是大写的,
 
我们没有必要把所有的字符都进行不区分大小写匹配,我们可以在打开标志,用(?i)的第二种形式马上关掉它:
    String regex = “(?i)b(?-i)ook”;

这样的话,只有b是区分大小写了,而(?-i)后面的还是得区分大小写匹配的。这样写可能看上去很不顺眼,我们还能使用第3种形式直接指定某些字符是不区分大小写的。
    String regex = “(?i:b)ook”;

这样的表达式与上面的那个在语义上是相同的。就效率上肯定是优于一下子开,一下子关的。可见内嵌标志表达式要比指定编译参数的功能强大许多。

 

使用建议:如果能确定某些字符的大小写时,尽量使用已确定的字符,对于不确定的可以采用 (?i:X) 的方式指定。因此打开不区分大小写开关时,对匹配的性能是有一定影响的。

 
实例7:多行匹配 。
/** Pattern Matcher */
    public static void RegexTypeEleven() {
        String str =
                "<table>                /n"
                    + "  <tr>                 /n"
                    + "    <td>               /n"
                    + "       Hello World!    /n"
                    + "    </td>              /n"
                    + "  </tr>                /n"
                    + "</table>";
        String regex = "<td>(.+?)</td>";
        Pattern pattern = Pattern.compile(regex);
        Matcher m = pattern.matcher(str);
        while (m.find()) {
            System.out.println(m.group(1).trim());
        }
    }
执行结果后,我们没有得到任何的结果。在默认的情况下.元字符是不能匹配行结束符的。
 
同样,可以像匹配大小写匹配那样使用编译参数:Pattern.DOTALL
实例7不能从str抽取出东西的,因为td的后面带有换行符,我们只要更改一下:
Pattern pattern = Pattern.compile(regex, Pattern.DOTALL);
这样就行了,如果td还得不区分大小写的话,再改成:
Pattern pattern = Pattern.compile(regex, Pattern.DOTALL | Pattern.CASE_INSENSITIVE);
当然和 Pattern.CASE_INSENSITIVE 一样,Pattern.DOTALL 也有内嵌标志表达式,即(?s),s的意思表示 single-line 就是忽略换行符什么的,只看成单行进行处理。
这个表达式使用内嵌 (?s) 的话可以改为:
String regex = "(?s)<td>(.+?)</td>";
如果还要不区分大小写的话,再加上 i 标志:
String regex = "(?s)(?i)<td>(.+?)</td>";
但这样显得很拖沓,可以把它们合并起来:
String regex = "(?is)<td>(.+?)</td>";    //秩序无所谓
 
Negative Lookahead是什么?
个人理解为缝隙匹配,接下来我们通过实例进行分析。
实例1:不以www开头。
/** Negative Lookahead的应用 */
public static void RegexNegaTiveOne(){
        String[] strs = {"abc1232", "wwwadsf", "awwwfas",
                         "wwadfsf", "", "ww", " ", "www" };
        String regex = "(?!^www).*";
        for (String str : strs) {
            System.out.println(str+"------>"+str.matches(regex));
        }
    }
前面我们讲过,^元字符表示行的开始。那么上述的实例中,^www的就是意思就是以www开头,但是前面添加了?!的符号,?!是什么意思呢?
?!就是缝隙匹配中的一种,?!x表示字符间缝隙后面不允许出现x字符。那么?!^www表达式的意思就是开头的缝隙后面不能出现www。
 
大家是不是还在思考“开头的缝隙后面”是什么意思呀?接下来我们进一步说明。
实例2:从字符串中截取出我们组(我们开发小组- -!)所有人的名字。
 /** Negative Lookahead */
    public static void RegexNegaTiveTwo(){
        String strs ="ZhouguokuLixinZhangchunchaoQiuhuHuangzhiguoWubaoquanZhangfeiChenleiGenghaiqingHuonanHanxiaodong";
        String regex = "(?=[A-Z])";
        String[] array=strs.split(regex);
        for(String str: array){
            System.out.println(str);
        }
    }
?=x指缝隙后面必须出现x字符。那么我们很容易去理解(?=[A-Z])的意思。它指缝隙后面必须出现A-Z大写字母,然后我们通过这个匹配的缝隙去分割。
 
通过运行刚才的程序,我们发现多出一行空行,这是什么原因呢?
空行
Zhouguoku
Lixin
Zhangchunchao
......
我们再来看下刚才的字符串。()
ZhouguokuLixinZhangchunchaoQiuhuHuangzhiguoWubaoquan
我们刚才的正则表达式想要表达的意思是:
Zhouguoku | Lixin | Zhangchunchao | Qiuhu | Huangzhiguo | Wubaoquan
在他们的之间的,按照|这个缝隙去分割。然而我们忽略了一个问题,那就是在Zhouguoku之前也是有缝隙的。字符串分割如下:
| Zhouguoku | Lixin | Zhangchunchao | Qiuhu | Huangzhiguo | Wubaoquan
所以会多出一行空行。那么实例1中的”开头的缝隙后面”这句话,也应该可以理解了。
那我们如何去掉多出的空行呢?
 
实例3:从字符串中截取出我们组所有人的名字,并且去掉多出的空行。
 /** Negative Lookahead */
    public static void RegexNegaTiveThree(){
        String strs ="ZhouguokuLixinZhangchunchaoQiuhuHuangzhiguoWubaoquanZhangfeiChenleiGenghaiqingHuonanHanxiaodong";
        String regex = "(?<!^)(?=[A-Z])";
        String[] array=strs.split(regex);
        for(String str: array){
            System.out.println(str);
        }
    }
这次大家再次运行,空行就没有了。我们只是修改了前面的表达式,那?<!^的作用肯定就是为了去掉空行的。 ?<!^的意思是指:表示缝隙不允许前面是行的开始,即缝隙不能出现在首字母的前面。
 
通过前面的例子,我们队缝隙匹配已经了解了。现在我们进行整理下。
缝隙匹配有以下四种表达式:
(?=X) 
(?!X) 
(?<=X) 
(?<!X)
 
(?!) 表示缝隙后面不允许出现的东西
(?<!) 表示缝隙前不允许出现的东西。
(?=) 表示缝隙后允许出现的东西。
(?<=) 表示缝隙前允许出现的东西。
最后给出一些常用的正则表达式:
 
匹配中文字符: [/u4e00-/u9fa5]
匹配Email地址:/w+([-+.]/w+)*@/w+([-.]/w+)*/./w+([-.]/w+)*
匹配网址URL:[a-zA-z]+://[^/s]*
匹配身份证:/d{17}[/d|X]|/d{15}
匹配ip地址:((2[0-4]/d|25[0-5]|[01]?/d/d?)/.){3}(2[0-4]/d|25[0-5]|[01]?/d/d?
匹配正整数:^[1-9]/d*$
匹配负整数:^-[1-9]/d*$
匹配整数:^-?[1-9]/d*$ 
匹配非负整数(正整数 + 0):^[1-9]/d*|0$ 
匹配非正整数(负整数 + 0):^-[1-9]/d*|0$
匹配由26个英文字母组成的字符串:^[A-Za-z]+$
匹配由26个英文字母的大写组成的字符串:^[A-Z]+$
匹配由26个英文字母的小写组成的字符串:^[a-z]+$
匹配由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
匹配由数字、26个英文字母或者下划线组成的字符串:^/w+$

抱歉!评论已关闭.