JAVA正则表达式

正则表达式
常用语法
正则表达式的构造字符 匹配
X 字符X
\\ 反斜线字符
\0n 带有八进制值0的字符n(0<=n<=7)
\0nn 带有八进制值0的字符nn n(0<=n<=7)
\0mnn 带有八进制值0的字符mnn(0<=m<=3、0<=n<=7)
\xhh 带有十六进制值0Xr的字符hh
\uhhhh 带有十六进制值0x的字符hhhh
\t 制表符(‘\u0009’)
\n 换行符(‘\u0000A’)
\r 回车符(‘\u000D’)

[abc] a 、 b或c
[^abc] 任何字符,除了a、或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](减去)
[a-z&&[^m-p]] a 到 z,而非 m 到 p:[a-lq-z](减去)

点:“.” 点:任何字符(与行结束符可能匹配也可能不匹配)
\d 数字:[0-9]
\D 非数字[^0-9]
\s 空白字符[\t\n\x0B\f\t]
\S 非空白字符:[^\s]
\w 单词字符[a-zA-Z_0-9]
\W 非单词字符[^\w]

^ 行的开头
$ 行的结尾
\b 单词边界
\B 非单词边界
\G 上一个匹配的结尾
Greedy 尽可能多的匹配
X? X,一次或一次也没有
X* X,零次或多次
X+ X,一次或多次
X{n} X,恰好 n 次
X{n,} X,至少 n 次
X{n,m} X,至少 n 次,但是不超过 m 次
Reluctant 尽可能少的匹配
X?? X,一次或一次也没有
X*? X,零次或多次
X+? X,一次或多次
X{n}? X,恰好 n 次
X{n,}? X,至少 n 次
X{n,m}? X,至少 n 次,但是不超过 m 次
Possessive
X?+ X,一次或一次也没有
X*+ X,零次或多次
X++ X,一次或多次
X{n}+ X,恰好 n 次
X{n,}+ X,至少 n 次
X{n,m}+ X,至少 n 次,但是不超过 m 次

XY X 后跟 Y
X|Y X 或 Y
(X) X,作为捕获组

\n 任何匹配的 nth 捕获组

(?:X) X,作为非捕获组
捕获组可以通过从左到右计算其开括号来编号 例如,在表达式 ((A)(B(C))) 中,存在四个这样的组
1 ((A)(B(C)))
2 (A)
3 (B(C))
4 (C)
0 组零始终代表整个表达式,与括号无关
? 以 (?) 开头的组是纯的非捕获 组,它不捕获文本,也不针对组合计进行计数。

Java与perl
JAVA支持,但是perl不支持的。这个有很多的方面,现在只说一点:
Possessive quantifiers, which greedily match as much as they can and do not back off, even when doing so would allow the overall match to succeed
Possessive 数量词,它可以尽可能多地进行匹配并且不会回退,即使这样做导致所有匹配都成功时也如此

区分greedy 、reluctant、possessive
Greedy:匹配器尽可能多的接收输入的字符,当第一匹配尝试失败后,匹配器就会在接收到的输入字符串中后退一个字符再次尝试,直到成功或没有符合的字符
Reluctant 匹配器从接收到的第一个字符开始,逐步地一次读一个字符搜索匹配。
Possessive匹配器尽可能多的接收输入的字符,尝试一次匹配,如果失败就失败,不会像Greedy一样后退。
reluctant
[code]
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.regex.PatternSyntaxException;
public class TestRegex2 {

/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String str="taaadaadcaaddf";
/*
“[adc]*”尽可能的接收字符,从第二个字符开始接受,直到倒数第二个字符结束,
“[adc]*”捕获了:“aaadaadcaadd”

接着后面应该连接一个d,但是字符最后一个为f,这时就后退一个字符,再进行匹配,这时括号中(表示一个捕获组,从左到右,在这里表示第一个捕获组)接受了从第二个字符到倒数第三个字符,
“[adc]*”捕获了:“aaadaadcaad”
后退的倒数第二个字符刚好为d,这时匹配成功。

*/

Pattern p = Pattern.compile("([adc]*)d");
Matcher m = p.matcher(str);
print(m,"greedy");


/*
“[adc]*?”尽可能少的接收输入字符,首先是接收一个空字符,由于第一个字符为t,不是d,匹配不成功,接着一个字符,这时接受的为第二个字符a,试着匹配,由于第三个字符a,非d,接着接收两个字符,直到接收三个字符后匹配成功。如果需要的话从新的位置开始准备下一轮的匹配,

第后一次匹配成功为一个字符d,“[adc]*?”捕获的为一个空字符。
*/
Pattern p2 = Pattern.compile("([adc]*?)d");
Matcher m2 = p2.matcher(str);
print(m2,"reluctant");



/*
“[adc]*+”尽可能的接收字符,从第二个字符开始接受,直到倒数第二个字符结束,
“[adc]*+”捕获了:“aaadaadcaadd”,由于后面应该连接一个d,但是实际输入的为f,匹配失败,且不后退。最后没有匹配成功。
*/
Pattern p3 = Pattern.compile("([adc]*+)d");
Matcher m3 = p3.matcher(str);
print(m3,"possessive3");

/*
“[adc]*+”尽可能的接收字符,从第二个字符开始接受,直到倒数第二个字符结束,
“[adc]*+”捕获了:“aaadaadcaadd”,由于后面应该连接一个f,实际输入的为f,匹配成功。
*/

Pattern p4 = Pattern.compile("([adc]*+)f");
Matcher m4 = p4.matcher(str);
print(m4,"possessive4");
}

public static void print(Matcher m,String style){
System.out.println("\n"+style);
while(m.find()){
if(m.groupCount()>=1)
System.out.println("第一组捕获组为:"+m.group(1));

System.out.println(m.group()+" start:"+m.start()+" end:"+m.end());


}
}

}
[/code]


输出结果:

greedy
第一组捕获组为:aaadaadcaad
aaadaadcaadd start:1 end:13

reluctant
第一组捕获组为:aaa
aaad start:1 end:5
第一组捕获组为:aa
aad start:5 end:8
第一组捕获组为:caa
caad start:8 end:12
第一组捕获组为:
d start:12 end:13

possessive3

possessive4
第一组捕获组为:aaadaadcaadd
aaadaadcaaddf start:1 end:14


[code]

import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.regex.PatternSyntaxException;
public class TestRegular {

/**
* @param args
*/


public static String myStr = "" +
"<div id=\"head_link\" class=\"padding_nav\">" +
"<div class=\"toplinkbotton\"><a href=\"../tzgl/dealTzgl.do?action=view\" target=\"_blank\">通知信息</a></div>" +
"<div class=\"toplinkbotton\"><a href=\"../xxfb/dealXxfb.do?action=lmxxIndex&lmbh=gsxw\" target=\"_blank\">公司新闻</a></div>" +
"<div class=\"toplinkbotton\"><a href=\"../tpxw/dealTpxw.do?action=tpxwIndex&curpage=1\" target=\"_blank\">图片新闻</a></div>" +
"</div>";
public static void main(String[] args) {
// TODO Auto-generated method stub
String myRegular = "\\<\\s*a[^\\>]*\\s+href\\s*=\\s*([\"|'])([^\\>]*?)\\1[^\\>]*\\>([^\\</]+)\\</a[^\\>]*\\>";
Pattern p = Pattern.compile(myRegular,Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(myStr);

while(m.find()){
if(m.groupCount()>=2)
System.out.println("link:"+m.group(2));
if(m.groupCount()>=3)
System.out.println("text:"+m.group(3));
}
}

}


[/code]


忽略大小写

(?i)abc 表示abc都忽略大小写
a(?i)bc 表示bc忽略大小写
a((?i)b)c 表示只有b忽略大小写
也可以用Pattern.compile(rexp,Pattern.CASE_INSENSITIVE)表示整体都忽略大小写

后向引用(back referencing)
在规则表达式中引用以前已经匹配的模式。

String regex = "<h(4|3)>.*?</h(4|3)>";
String str = "<h3><h4>my.domin/index.jsp</h4><h4>href=\"my.domin/index.jsp</h4></h3>";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(str);
while(m.find()){
System.out.println(m.group());
}

输出结果为:
<h3><h4>my.domin/index.jsp</h4>
<h4>href="my.domin/index.jsp</h4>
我们可能并不想匹配上:<h3><h4>my.domin/index.jsp</h4>这种情况。这时可以用back referencing,
使用”\1,\2......\9”引用前面匹配上的子模式。

String regex = "<(h4|h3)>.*?</\\1>";
String str = "<h3><h4>my.domin/index.jsp</h4><h4>my.domin/index.jsp</h4></h3>";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(str);
while(m.find()){
System.out.println(m.group());
}

输出结果为:
<h3><h4>my.domin/index.jsp</h4><h4>my.domin/index.jsp</h4></h3>;

替换

String regex = "<(h4)>([^<>]*)</\\1>";
String str = "<h4>my.domin/index.jsp</h4><h4>my.domin/index.jsp</h4>";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(str);
while(m.find()){
System.out.println(m.group());
}
System.out.println("替换:");
System.out.println(m.replaceAll("<h2>$2</h2>"));

输出结果:
<h4>my.domin/index.jsp</h4>
<h4>my.domin/index.jsp</h4>
替换:
<h2>my.domin/index.jsp</h2><h2>my.domin/index.jsp</h2>

非捕获组
以 (?) 开头的组是纯的非捕获 组,它不捕获文本,也不针对组合计进行计数。就是说,如果小括号中以?号开头,那么这个分组就不会捕获文本,当然也不会有组的编号,因此也不存在Back 引用。
在Java中,支持的非捕获组,有如下几种:

正向预查,后向预查
负正向预查 负后向预查

(?=X) X,通过零宽度的正 lookahead
(?!X) X,通过零宽度的负 lookahead
(?<=X) X,通过零宽度的正 lookbehind
(?<!X) X,通过零宽度的负 lookbehind

这四个非捕获组用于匹配表达式X,但是不包含表达式的文本。
(?=X ) 零宽度正先行断言。仅当子表达式 X 在 此位置的右侧匹配时才继续匹配。例如,\w+(?=\d) 与后跟数字的单词匹配,而不与该数字匹配。此构造不会回溯。
(?!X) 零宽度负先行断言。仅当子表达式 X 不在 此位置的右侧匹配时才继续匹配。例如,例如,\w+(?!\d) 与后不跟数字的单词匹配,而不与该数字匹配。
(?<=X) 零宽度正后发断言。仅当子表达式 X 在 此位置的左侧匹配时才继续匹配。例如,(?<=19)99 与跟在 19 后面的 99 的实例匹配。此构造不会回溯。
(?<!X) 零宽度负后发断言。仅当子表达式 X 不在此位置的左侧匹配时才继续匹配。例如,(?<!19)99 与不跟在 19 后面的 99 的实例匹配
举例:
上面都是理论性的介绍,这里就使用一些例子来说明一下问题:
1、测试匹配性 (?<!4)56(?=9) 这里的含义就是匹配后面的文本56前面不能是4,后面必须是9组成。因此,可以匹配如下文本 5569 ,与4569不匹配。
2 、提取字符串 提取 da12bka3434bdca4343bdca234bm 提取包含在字符a和b之间的数字,但是这个a之前的字符不能是c,b后面的字符必须是d才能提取。
例如这里就只有3434这个数字满足要求。那么我们怎么提取呢?
首先我们写出提取这个字符串的表达式: (?<!c)a(\d+)bd 这里就只有一个捕获组(\d+)
JAVA代码片段如下:

Pattern p = Pattern.compile("(?<!c)a(\\d+)bd");
Matcher m = p.matcher("da12bca3434bdca4343bdca234bm");
while(m.find()){
System.out.println(m.group(1)); //我们只要捕获组1的数字即可。结果 3434
System.out.println(m.group(0)); // 0组是整个表达式,看这里,并没有提炼出(?<!c)的字符 。结果 a3434bd
}

可以看到,非捕获组,最后是不会返回结果的,因为它本身并不捕获文本。


优先级:


[table]
|高| \ |转义符|
| | (), [] |圆括号和方括号|
| | *, +, ?, {n}, {n,}, {n,m} |限定符|
| | ^, $, |位置和顺序|
|低| 一竖(这个编辑器显示不了) |“或”操作 |
[/table]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值