/**使用正则表达式的基本方法:
(一)建立
String regex="";//regex匹配
String input="";//input输入
Pattern p= Pattern.compile(regex);//将给定的正则表达式(regex)编译compile()到模式(Pattern)中。 static Pattern compile(String regex)
Matcher m=p.matcher(input);//创建匹配(match)给定输入(input)与此模式的匹配器(Matcher)。 Matcher matcher(CharSequence input)
(二)处理匹配结果
//如果是用regex匹配全部input则使用。尝试将整个区域与模式匹配:boolean matches()
m.matches()
//通常只需要匹配部分input,则使用m.find() 尝试查找与该模式匹配的输入序列的下一个子序列:boolean find([int start])
//抛出:IndexOutOfBoundsException - 如果开始点小于零或大于输入序列的长度。
int tmpStart=0
while(m.find())
{
//...
tmpStart=m.end();//end()返回的是当前与模式匹配的子序列的结尾的位置。
}
(三)关于捕获
regex中()表示需要捕获的群组,匹配后,得到一个数组存放所有的捕获。
返回此匹配器模式中的捕获组数:int groupCount()//捕获是从1开始计算,0始终表示整个regex,所以想返回整个匹配的子序列可以用m.group()。
返回由以前匹配操作所匹配的输入子序列: String group()
for(int i=0;i<=m.groupCount();++i)//i=0表示m.group(0)即整个regex的匹配
{
System.out.print(m.group(i));
System.out.print(" ,starts at pos:"+m.start(i));
System.out.print(" ,ends at pos:"+m.end(i));
System.out.println();
}
(四)替换
1.替换模式与给定替换字符串相匹配的输入序列的每个子序列。String replaceAll(String replacement)
m.replaceAll("#");//input的所有与regex匹配的子序列都被替换成"#";
2.替换模式与给定替换字符串匹配的输入序列的第一个子序列。String replaceFirst(String replacement)
m.replaceFirst("#");//input第一个与regex匹配的子序列被替换成"#";
3.用捕获的内容进行替换
m.replaceFirst("$1");//用第一个捕获的内容替换整个与regex匹配的子序列。
String forMatch="15851844444aasdddd15851866666ddd15851822222ddd15851899999";//ddd15851877777
String regex="1[3458]\\d{4}(\\d)\\1{4}";
Pattern p=Pattern.compile(regex);
Matcher m=p.matcher(forMatch);
int tmpStart=0;
int cntMatches=0;
while(m.find(tmpStart))
{
tmpStart=m.end();
System.out.println("matches "+(++cntMatches)+" : ");
for(int i=0;i<=m.groupCount();++i)
{
System.out.print("match "+i+" : ");
System.out.print(m.group(i));
System.out.print(" ,starts at pos:"+m.start(i));
System.out.print(" ,ends at pos:"+m.end(i));
System.out.println();
}
System.out.println();
}
*/
/**
练习题: 写一个正则表达式,可以匹配尾号5连的手机号。规则: 第1位是1,第二位可以是数字3458其中之一,后面4位任意数字,最后5位为任意相同的数字。
例如:18601088888、13912366666
@author rexih
0.首先根据题目要求制作一个随机文本文件,文件内有字母和手机号码
a.创建一个手机号码生成器
规则: 第1位是1,第二位可以是数字3458其中之一,后面9位任意数字。
b.将号码随机插入到随机字母文本中。
1.建立一个ArrayList<String>存储捕获到的手机号码,建立一个字符缓冲区sb存放将作为输入的字符序列;
2.读取文件的内容 src:文件 FileInputStream //dest:屏幕
3.通过read(buf)方法读取输入流的字节数据,并将读取到的字节数据附加到字符缓冲区末尾
4.将sb转换成输入input
5.编写regex
6.将regex编译进模式Pattern
7.获取匹配器Matcher m
8.通过m的find()方法寻找每一个匹配,并通过group()获取符合要求的电话号码
9.将电话号码的字符串存入ArrayList<String>
10.打印集合中的所有电话号码。
*/
import java.io.*;
import java.util.regex.*;
import java.util.*;
public class Test
{
public static void main(String[] args) //throws Exception
{
ArrayList<String> al=new ArrayList<String>();
InputStream in=null;
byte[] buf=new byte[1024];
int cntBuf=0;
StringBuilder sb=new StringBuilder();
//生成一个用于演示的文本文件
File f=buildAFile();
try
{
//读取文件的内容 src:文件 FileInputStream
in=new FileInputStream(f);
//通过read(buf)方法读取输入流的字节数据
while(-1!=(cntBuf=in.read(buf)))
{
//将读取到的字节数据附加到字符缓冲区末尾
sb.append(new String(buf,0,cntBuf));
}
} catch (IOException e)
{
throw new RuntimeException("read file failed");
}
finally
{
//关闭输入流
if(null!=in)
{
try
{
in.close();
} catch (IOException e)
{
throw new RuntimeException("input close failed");
}
}
}
//准备好正则表达式使用的输入
String input=sb.toString();
/*准备好正则表达式:
按照题目要求:
第一位为 1 1
第二位为3458之一 [3458]
中间4位任意 \d{4}
后5位相同 (\d)\1{4} //(\d)表示将这个数字捕获因为5个数字相同,所以该数字之后4个数字应该与之相同,即与\1相同,也就是\1{4}
*/
String regex="1[3458]\\d{4}(\\d)\\1{4}";
//将正则表达式编译进模式
Pattern p=Pattern.compile(regex);
//获取输入和模式的匹配器m
Matcher m=p.matcher(input);
//获取下一次匹配的起始位置(上次匹配结果的末尾)
int tmpStart=0;
//因为号码不止一个所以需要多次匹配以获取所有号码
while(m.find(tmpStart))
{
tmpStart=m.end();//获取下一次匹配的起始位置(上次匹配结果的末尾)
newPrint("get a phone number: "+m.group());//m.group()获取本次匹配的子序列。
al.add(m.group());//添加入“电话本”
}
newPrint("All the cell phone numbers stored in ArrayList:");
int cnt=0;
for(String s:al)
{
newPrint((++cnt)+":\t"+s);
}
newPrint("The orginal file is saved at:\n"+f.getAbsolutePath());
}
//生成一个文件
public static File buildAFile()
{
//创建一个File对象用于保存文件,并且返回给主函数调用。
File f=new File("regex.txt");
FileOutputStream fout=null;
try
{
//dest是文件,使用FileOutputStream
fout=new FileOutputStream(f);
writeContent(fout);//向文件写入内容
} catch (IOException e)
{
throw new RuntimeException("builing a file failed");
}
finally
{
//关闭资源
if(null!=fout)
{
try
{
fout.close();
} catch (IOException e)
{
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
return f;
}
//向输出流写入内容
public static void writeContent(OutputStream out)throws IOException//异常返回给invoker处理
{
int offset=0;
for(int i=0;i<100;++i)
{
//每一百个字母中随机选择一个位置,随机判断是否用电话号码替代掉,概率为1/10
offset=getRand(0,99);
for(int j=0;j<offset;++j)
{
out.write(getRandAlphabet());
}
//判断该字符是否用电话号码替代掉,概率为1/10
if(5==getRand(0,10))
{
out.write(phoneNumGen());
}else
{
out.write(getRandAlphabet());
}
for(int j=offset+1;j<100;++j)
{
out.write(getRandAlphabet());
}
}
}
//使用Math类的random()方法获取[0.0,1.0)的随机数乘以length+begin再取整则可以得到[begin,begin+length)的整数
public static int getRand(int begin,int length)
{
return (int)(Math.random()*length+begin);
}
//随机获取一个小写字母a的ascii为97,一共有26个字母
public static char getRandAlphabet()
{
return (char)getRand(97,26);
}
//创建一个手机号码生成器。规则: 第1位是1,第二位可以是数字3458其中之一,后面9位任意数字。
public static byte[] phoneNumGen()
{
//48是0的ascii码
final int ZERO=48;
//为了方便字节流输出数据,将返回值定义为byte[]
byte[] phoneNum=new byte[11];
//step1:第一位为1
phoneNum[0]=(byte)(1+ZERO);
//step2:随机获取第二位的数字
switch(getRand(1,4))
{
case 1:
phoneNum[1]=(byte)(3+ZERO);
break;
case 2:
phoneNum[1]=(byte)(4+ZERO);
break;
case 3:
phoneNum[1]=(byte)(5+ZERO);
break;
case 4:
phoneNum[1]=(byte)(8+ZERO);
break;
}
//step3:随机写入中间4位
for(int i=2;i<6;++i)
{
phoneNum[i]=(byte)getRand(ZERO,10);
}
//step4:为了让程序结果更能说明问题,先生成一个随机数,若是0则后五位随机,若是1则后五位相同
if(0==getRand(0,2))
{
for(int i=6;i<11;++i)
{
phoneNum[i]=(byte)getRand(ZERO,10);
}
}
else
{
byte tmp=(byte)getRand(ZERO,10);
for(int i=6;i<11;++i)
{
phoneNum[i]=tmp;
}
}
return phoneNum;
}
//简化书写,打印简单的信息。
public static void newPrint(Object obj)
{
System.out.println(obj);
}
}
黑马程序员——正则表达式(1)
最新推荐文章于 2022-10-29 17:07:07 发布