1 正则表达式——功能:匹配、切割、替换
正则表达式:符合一定规则的表达式。
作用:用于专门操作字符串。
特点:用一些特定的符号来表示一些代码操作,这样简化了书写。
所以学习正则表达式,就是在学习一些特殊符号的使用。
好处:可以简化对字符串的复杂操作。
弊端:符号定义越多,正则表达式越长,阅读性越差。
正则表达式功能:
1,匹配:String类中的 matches方法。
matches( regex):用正则表达式的规则匹配整个字符串,只要有一处不符合规则,就匹配结束,返回false。
2,切割:String类中的 split方法。
split( regex):根据正则表达式split进行切割当前字符串str。
3,替换:String类中的 replaceAll方法。
replaceAll( regex, newStr):根据正则表达式的规则,用新字符串替换正则表达式定义的字符串。
2 正则表达式规则
字符 :
x 字符 x
\\ 反斜线字符
\0n 带有八进制值 0 的字符 n (0 <= n <= 7)
\0nn 带有八进制值 0 的字符 nn (0 <= n <= 7)
\0mnn 带有八进制值 0 的字符 mnn(0 <= m <= 3、0 <= n <= 7)
\xhh 带有十六进制值 0x 的字符 hh
\uhhhh 带有十六进制值 0x 的字符 hhhh
\t 制表符 ('\u0009')
\n 新行(换行)符 ('\u000A')
\r 回车符 ('\u000D')
\f 换页符 ('\u000C')
\a 报警 (bell) 符 ('\u0007')
\b 匹配一个单词边界,也就是指单词和空格间的位置
\e 转义符 ('\u001B')
\cx 对应于 x 的控制符
字符类:
[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](减去)
[a-z&&[^m-p]] a 到 z,而非 m 到 p:[a-lq-z](减去)
预定义字符类:
. 任何字符(与行结束符可能匹配也可能不匹配)
\d 数字:[0-9]
\D 非数字: [^0-9]
\s 空白字符:[ \t\n\x0B\f\r]
\S 非空白字符:[^\s]
\w 单词字符:[a-zA-Z_0-9]
\W 非单词字符:[^\w]
Greedy 数量词:
X? X,一次或一次也没有
X* X,零次或多次
X+ X,一次或多次
X{n} X,恰好 n 次
X{n,} X,至少 n 次
X{n,m} X,至少 n 次,但是不超过 m 次。
3 组和捕获及正则表达式实例
组合捕获
捕获组可以通过从左到右计算其开括号来编号。例如,在表达式 ((A)(B(C))) 中,存在四个这样的组:
1 ((A)(B(C)))
2 \A
3 (B(C))
4 (C)
组0始终代表整个表达式。
之所以这样命名捕获组是因为在匹配中,保存了与这些组匹配的输入序列的每个子序列。
捕获的子序列稍后可以通过 Back 引用在表达式中使用,也可以在匹配操作完成后从匹配器获取。
与组关联的捕获输入始终是与组最近匹配的子序列。如果由于量化的缘故再次计算了组,
则在第二次计算失败时将保留其以前捕获的值(如果有的话)例如,将字符串 "aba" 与表达式 (a(b)?)+ 相匹配,
会将第二组设置为 "b"。在每个匹配的开头,所有捕获的输入都会被丢弃。
以 (?) 开头的组是纯的非捕获组,它不捕获文本,也不针对组合计进行计数。
应用实例:
需求:对QQ号码进行校验,要求:5~15位,0不能开头,只能是数字。
原方式:这种方式使用String类中的方法,进行组合完成了需求。但是代码过于复杂。
代码示例:
class RegexDemo{
public static void main(String[] args){
checkQQ_1();
checkQQ();
demo();
splitDemo();
String str = "wer1389980000ty12345uiod2345452452454f";//将字符串中数字替换成#
replaceAllDemo(str,"\\d{5,}","#"); //\\d{5,}:连续0到9的数字至少5个。
String strr = "erkktytuqqquizzzzzo"; //将叠词替换成相应的单个字符。
replaceAllDemo(strr,"(.)\\1+","$1");//$1 表示正则表达式中的第一组,即()中的内容,符号$有特殊含义。
}
//根据正则表达式替换
public static void replaceAllDemo(String str, String regex, String newStr){
str = str.replaceAll(regex,newStr); //String类的replaceAll方法,可以用正则替换
System.out.println(str);
}
//根据正则表达式切割字符串
public static void splitDemo(){
/* String str = "zhangsan....lisi...wangwu";
String regex = "\\.+"; */ //按照多个点来切割,见正则中的Greedy数量词
String str = "crkkadfddalpezzzzkjgf";
String regex = "(.)\\1+"; //按照叠词完成切割,可以将规则封装成一个组,用()括起来。
//组的出现都有编号,从1开始。想要使用已有的组可以通过 \n的形式获取,n是编号
String[] arr = str.split(regex); //根据叠词分割
for(String s : arr){
System.out.println(s);
}
}
//正则表达式定义规则:字符,字符类,预定义字符类,Greedy数量词
public static void demo(){
String str = "b9";
String regex = "[a-zA-Z]\\d";
boolean b = str.matches(regex); //匹配
System.out.println(b);
}
//正则表达式方式
//boolean matches(String regex); 告知此字符串是否匹配给定的正则表达式。
public static void checkQQ(){
String qq = "275150374";
String regex = "[1-9][0-9]{4,14}";
boolean flag = qq.matches(regex); //匹配
if(flag)
System.out.println(qq+"...is ok");
else
System.out.println(qq+"...不合法");
}
//原方式,不使用正则表达式。
public static void checkQQ_1(){
String qq = "111111111111111";
int len = qq.length();
if(len>=5 && len<=15){
if(!qq.startsWith("0")){
char[] arr = qq.toCharArray();
boolean flag = true;
for(int x=0; x<arr.length; x++){
if(!(arr[x]>='0' && arr[x]<='9')){
flag = false;
break;
}
}
if(flag)
System.out.println("QQ: "+qq);
else
System.out.println("出现非法字符");
}
else{
System.out.println("不能以0开头");
}
}
else{
System.out.println("长度错误");
}
}
}
4 正则表达式功能——获取(匹配器Matcher)
获取:将字符串中的符合规则的子串取出。
操作步骤:
1,将正则表达式封装成对象。
2,让正则对象和要操作的字符串相关联。
3,关联后,获取正则匹配引擎。
4,通过引擎,对符合规则的子串进行操作,比如取出。
代码示例:
import java.util.regex.*;
class RegexDemo2 {
public static void main(String[] args){
getDemo();
}
public static void getDemo(){
String str = "ming tian jiu yao fang jia la";
//正则表达式,\b是单词边界符。
String regex = "\\b[a-z]{4}\\b";
//将正则封装成对象。
Pattern p = Pattern.compile(regex);
//让正则对象和要作用的字符串相关联。获取匹配器对象。
Matcher m = p.matcher(str);
//str.matches(regex);//其实String类中的matches方法,用的就是Pattern和Matcher对象来完成的,
//只不过被String的方法封装后,用起来较为简单,但是功能却单一。
while(m.find()){ //判断是否有符合匹配器的子串。
System.out.println(m.group()); //返回由以前匹配操作所匹配的输入子序列,返回匹配结果。
//匹配的子串的开始脚标和结束脚标,包含头不包含尾。
System.out.println("位置:"+m.start()+"..."+m.end());
}
}
}
匹配结果:
5 正则表达式练习★
练习1:
需求:将下列字符串转换成:我要学编程
到底用四种功能中的哪一个呢?或者哪几个呢?
思路方式:
1,如果只想知道该字符是对还是错,使用匹配。
2,想要将已有的字符串变成另一个字符串,替换。
3,想要按照自定的方式将字符串变成多个字符串,切割、获取规则以外的子串。
4,想要拿到符合需求的字符串子串,获取、获取符合规则的子串。
练习2:
需求:将ip地址进行地址段顺序的排序。
192.68.1.254 102.49.23.13 10.10.10.10 2.2.2.2 8.109.30.90
还按照字符串自然顺序,只要让它们每一段都是3位即可。
1,按照每一段需要的最多的0进行补齐,那么每一段至少保证有3位。
2,将每一段只保留3位。这样,所有的ip地址段都是每一段3位。
练习3:
需求:对邮件地址进行校验。
代码示例:
import java.util.regex.*;
import java.util.*;
class RegexTest{
public static void main(String[] args){
test_1();
ipSort();
checkMail();
}
public static void test_1(){
String str = "我我...我我...我要..要要...要要...学学学..学学..编编...编编..编程..程程.程程";
/* 将已有字符串变成另一个字符串。使用替换功能。
1,可以先将 “.”去掉。
2,再将多个重复的内容变成单个内容。 */
str = str.replaceAll("\\.+","");
System.out.println(str);
//$1 表示正则表达式中的第一组,即()中的内容,符号$有特殊含义.
str = str.replaceAll("(.)\\1+","$1");
System.out.println(str);
}
public static void ipSort(){
String ip = "192.68.1.254 102.49.23.13 10.10.10.10 2.2.2.2 8.109.30.90";
ip = ip.replaceAll("(\\d+)","00$1"); //每一段都补两个0
System.out.println(ip);
ip = ip.replaceAll("0*(\\d{3})","$1"); //每一段保留三位
System.out.println(ip);
String[] arr = ip.split(" ");
TreeSet<String> ts = new TreeSet<String>(); //TreeSet集合,自然排序
for(String s : arr){
ts.add(s);
}
for(String s : ts){
System.out.println(s.replaceAll("0*(\\d+)","$1")); //把开头的0去掉
}
}
public static void checkMail(){
String mail = "abc123@sina.com";
String reg = "[a-zA-Z0-9_]+@[a-zA-Z0-9]+(\\.[a-zA-Z]+)+";//较为精确的匹配
String regex = "\\w+@\\w+(\\.\\w+)+"; //相对不太精确的匹配
System.out.println(mail.matches(regex));
}
}
6 抓取电子邮件地址和URL类
获取指定文档中的邮件地址。
使用获取功能,Pattern Matcher
URL:java.net包的URL类、URLConnection类
调用URL对象的openConnection()方法创建连接对象,返回URLConnection对象。
URLConnection类中
getInputStream():返回从此打开的链接读取数据的读取流,读取URL资源。
getOutputStream():返回写入到此链接的输出流。
代码示例:
import java.util.regex.*;
import java.io.*;
import java.net.*;
class RegexTest2 {
public static void main(String[] args) throws Exception{
getMails();
getMails_1();
}
//从文档中抓取电子邮件地址
public static void getMails() throws Exception{
BufferedReader bufr =
new BufferedReader(new FileReader("e:\\mail.txt"));
String mailregex = "\\w+@\\w+(\\.\\w+)+";
Pattern p = Pattern.compile(mailregex);//将正则封装成对象
String line = null;
while((line=bufr.readLine())!=null){
Matcher m = p.matcher(line); //正则对象和字符串关联,获取匹配器
while(m.find()){ //是否有符合匹配器的子串。
System.out.println(m.group()); //返回匹配的子序列,返回匹配结果。
}
}
}
//从网页中抓取电子邮件地址
public static void getMails_1() throws Exception{
URL url = new URL("http://192.168.0.100:8080/myweb/mail.html");
URLConnection conn = url.openConnection(); //创建连接对象。
BufferedReader bufIn =
new BufferedReader(new InputStreamReader(conn.getInputStream())); //读取URL资源的读取流
String mailregex = "\\w+@\\w+(\\.\\w+)+";
Pattern p = Pattern.compile(mailregex); //把正则表达式封装成对象
String line = null;
while((line=bufIn.readLine())!=null){
Matcher m = p.matcher(line); //创建匹配器,关联正则对象和字符串
while(m.find()){ //判断是否有匹配的子串
System.out.println(m.group()); //返回匹配结果
}
}
}
}