------- android培训、java培训、期待与您交流! ----------
符合一定规则的表达式。
作用:用于专门操作字符串。
特点:用一些特定的符号来表示一些代码操作,这样就简化了书写。
好处:可以简化对字符串的复杂操作。
弊端:符号定义越多,正则越长,阅读性越差。
1.匹配:String类中的 matches方法,用规则匹配整个字符串,只要有一处不符合规则,就匹配结束,返回false。
2.切割:String类中的 split方法。
3.替换:String类中的 replaceAll方法。
4.获取:将字符串中符合规则的子串取出。
操作步骤:1.将正则表达式封装成对象。
2.让正则对象和要操作的字符串相关联。
3.关联后,获取正则匹配引擎。
4.通过引擎,对符合规则的子串进行操作。比如:取出。
String类中有一个方法:
boolean |
matches(String regex) (regex:正则表达式)告知此字符串是否匹配给定的正则表达式。 |
点击“正则表达式”会跳转到 java.util.regex 类 Pattern
正则表达式的编译表示形式:
字符类 | |
---|---|
[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](减去) |
一个方括号代表一个字符,里面是可以可以匹配的值。如果从哪到哪一个范围内都可以匹配,就写[a-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 次 |
使用正则表达式,校验QQ号码:
class RegexTest
{
public static void main(String[] args)
{
//checkQQ_1("1245gsdf644");
checkQQ_2("123555");
}
//使用正则表达式,校验QQ号码
public static void checkQQ_2(String QQ)
{
//boolean matches(String regex);
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:"+QQ);
}
}
//对QQ号码进行校验
//长度:5~15、0不能开头、只能是数字
//这种校验方法,使用String类和Integer类中的方法进行组合,但是代码过于复杂。
public static void checkQQ_1(String QQ)
{
int len = QQ.length();
if(len>=5 && len<=15)
{
if(!QQ.startsWith("0"))//Integer.parseInt("12a");NumberFormatException
{
try
{
long qq = Long.parseLong(QQ);
System.out.println("QQ号:"+qq);
}
catch (NumberFormatException e)
{
System.out.println("出现非法字符");
}
// char[] arr = QQ.toCharArray();
// boolean flag = true;
// for(int x=0; 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("长度错误");
}
}
}
作业:
匹配手机号
手机号段只有:13***,15***,18***
class RegexTest
{
public static void main(String[] args)
{
checkPhoneNumber("13121456789");
}
/*
匹配手机号
手机号段只有:13***,15***,18***
*/
public static void checkPhoneNumber(String tel)
{
String regex = "[1][358]\\d{9}";
System.out.println( tel.matches(regex) );
}
}
String[] |
split(String regex) 根据给定正则表达式的匹配拆分此字符串。 |
为了让规则的结果被重[chóng]用,可以将规则封装成一个组,用()完成。组的出现都要编号,从1开始。想要使用已有的组,可以通过 \n 的形式获取。(n是组的编号)
((())()) 代表几个组呢?有几个左括号就有几组。那么哪个是第一组呢?第一个左括号就是第一个组。
组和捕获
捕获组可以通过从左到右计算其开括号来编号。例如,在表达式 ((A)(B(C))) 中,存在四个这样的组:
1 ((A)(B(C))) 2 \A 3 (B(C)) 4 (C)
组零始终代表整个表达式。
class RegexSplit
{
public static void main(String[] args)
{
//splitStr( "hello,,,world,,,!" , ",+" );//按照多个逗号来切。
//splitStr( "hello.world.!" , "\\." );//按照点来切,点是正则表达式里的特殊符号,所以需要转义。
//splitStr( "C:\\abc\\a.txt" , "\\\\" );//字符串里的斜线要出来就是一对。
//splitStr( "goodaamorningkk!" , "(.)\\1" );//按照叠词切。把要重用的部分用小括号括起来封装成为一个组。
//这个组封装起来以后会有一个自动的编号,从1开始。
//第二个位置和第一组那个结果是一致的,怎么使用这个组呢?\1
splitStr( "goodaaamorningzzzz!" , "(.)\\1+" );//用多个重复的任意字符完成切割。
}
public static void splitStr(String str, String regex)
{
String[] arr = str.split(regex);
for(String subStr : arr)
{
System.out.println(subStr);
}
}
}
String |
replaceAll(String regex,String replacement) 使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。 |
用$获取组的概念(在正则表达式外面获取):$1代表:获取前一个规则里面的第一个组。
class RegexSplit
{
public static void main(String[] args)
{
String str = "fhj5365474iah5435453ghia534543ghi";//将字符串中的数字替换成#。
replaceAllDemo( str , "\\d{5,}" , "#" );
String str1 = "goodaaamorningzzzz!";//将将重叠的字符替换成一个字符。zzzz->z
replaceAllDemo( str1 , "(.)\\1+" , "$1" );//$1代表:拿前一个规则里面的第一个组。
}
public static void replaceAllDemo(String str, String regex, String replacement)
{
str = str.replaceAll(regex, replacement);
System.out.println(str);
}
}
正则到底属于谁呢?属于:
java.util.regex
类 Pattern
public final class Pattern
extends Object
implements Serializable正则表达式的编译表示形式。
没有构造函数,有一静态方法可以得到本类对象。
static Pattern |
compile(String regex) 将给定的正则表达式编译到模式中。 |
正则与要作用的字符串相关联,用此方法:
Matcher |
matcher(CharSequence input) 创建匹配给定输入与此模式的匹配器。 |
java.lang 接口 CharSequence 是 char
值的一个可读序列。有个直接已知子类是String。
Matcher 类型的返回值是此模式的新匹配器或者称引擎。
java.util.regex
类 Matcher
通过解释 Pattern
对character sequence
执行匹配操作的引擎。
boolean |
matches() 尝试将整个区域与模式匹配。 |
获取怎么获取呢?先查找:
boolean |
find() 尝试查找与该模式匹配的输入序列的下一个子序列。 |
找到了再用group方法获取:
String |
group() 返回由以前匹配操作所匹配的输入子序列。 |
int |
start() 返回以前匹配的初始索引。 |
int |
end() 返回最后匹配字符之后的偏移量。 |
"ming tian jiu yao fang jia le, da jia.";//要把这里面连续三个字符相连的子串取出来。
import java.util.regex.*;
class RegexDemo
{
public static void main(String[] args)
{
getDemo();
}
public static void getDemo()
{
String str = "ming tian jiu yao fang jia le, da jia.";//要把这里面连续三个字符相连的子串取出来
//str = "01234567";
//String regex = "[1-9]\\d{4,14}";
String regex = "\\b[a-z]{4}\\b";
//将规则封装成对象
Pattern p = Pattern.compile(regex);
//让正则与要作用的字符串相关联,得到引擎。
Matcher m = p.matcher(str);
//使用引擎对字符串进行操作。
//System.out.println(m.matches());
//其实String类中的matches方法,用的就是Pattern和Matcher对象来完成的。
//只不过被String类的方法封装后,用起来简单,功能却单一。
//想要用到更多的方法还是要找到Matcher这个对象,我们发现它里面也有replaceAll方法,
//除了这些方法外,它还有更牛的方法,String没有封装过的。比如:获取。
//matches作用于整个字符串,索引位置改变到正则表达式匹配后的位置。
while(m.find())//先查找
{
System.out.println(m.group());//再获取
System.out.println(m.start()+"......"+m.end());
}
}
}
将下列字符串转成:我要学编程。
"我...我.我我.我要.要.要..要要..要.学学学.学.学学..编编编..编.编程..程程程.程"
class RegexTest1
{
public static void main(String[] args)
{
test();
}
public static void test()
{
String str = "我...我.我我.我要.要.要..要要..要.学学学.学.学学..编编编..编.编程..程程程.程";
String reg1 = "[\\.]+";//定义正则表达式:一个或多个点。
String[] arr = str.split(reg1);//用一个或多个点切割字符串,变成字符串数组。
StringBuilder sb = new StringBuilder();//将字符串数组里的每一个字符串元素添加到StringBuilder里。
for(String string : arr)
{
sb.append(string);
}
str = new String(sb); //将StringBuilder变成新的字符串。
System.out.println(str);
//"我我我我我要要要要要要学学学学学学编编编编编程程程程程"
String reg2 = "(.)\\1+";//定义正则表达式:重复的任意字符(两个或两个以上)
str = str.replaceAll(reg2,"$1");//用前一个正则表达式里面的第几个组来替换符合前一个正则的字符
System.out.println(str);
//我要学编程
}
}
更简捷,两步完成。
class RegexTest1
{
public static void main(String[] args)
{
test();
}
/*
需求:
将下列字符串转成:我要学编程.
到底用四种功能中的哪一个呢?或者哪几个呢?
思路方式:
1,如果只想知道该字符是否对还是错,使用匹配。
2,想要将已有的字符串变成另一个字符串,替换。
3,想要按照自定的方式将字符串变成多个字符串。切割。获取规则以外的子串。
4,想要拿到符合需求的字符串子串,获取。获取符合规则的子串。
*/
public static void test()
{
String str = "我...我.我我.我要.要.要..要要..要.学学学.学.学学..编编编..编.编程..程程程.程";
/*
将已有字符串变成另一个字符串。使用 替换功能。
1,可以先将 . 用 "" 替换。
2,在将多个重复的内容变成单个内容。
*/
str = str.replaceAll("\\.+","");
System.out.println(str);
//我我我我我要要要要要要学学学学学学编编编编编程程程程程
str = str.replaceAll("(.)\\1+","$1");
System.out.println(str);
//我要学编程
}
}
192.68.1.254 102.49.23.013 10.10.10.10 2.2.2.2 8.109.90.30
将ip地址进行地址段顺序的排序。
import java.util.TreeSet;
import java.util.Comparator;
class RegexTest2
{
public static void main(String[] args)
{
test();
}
/*
192.68.1.254 102.49.23.013 10.10.10.10 2.2.2.2 8.109.90.30
将ip地址进行地址段顺序的排序。
*/
public static void test()
{
String str = "192.68.1.254 102.49.23.013 10.10.10.10 2.2.2.2 8.109.90.30";
String[] arr = str.split(" ");//将ip字符串按照空格切开,变成一个一个的ip字符串。
/*
192.68.1.254
102.49.23.013
10.10.10.10
2.2.2.2
8.109.90.30
*/
TreeSet ts = new TreeSet(new IntComparator());//TreeSet集合是会自动排序的集合,传入自定义的比较器。
for(String ip : arr)//遍历ip字符串数组
{
String[] ipHead = ip.split("\\.");//ip地址字符串按照 "." 切开。
ts.add(ipHead[0]);//将ip地址的头段存入TreeSet集合,以便于排序。
}
//排序后的ip头
System.out.println(ts);//[2, 8, 10, 102, 192]
StringBuilder sb = new StringBuilder();
for(String ipHead : ts)//遍历TreeSet集合,以便将ip头与原ip字符串做匹配。
{
for(String ip : arr)//遍历ip字符串数组。
{
if(ip.startsWith(ipHead+"."))//如果这个ip字符串是以ip头加点开头的话,
{
sb.append(ip+" ");//就将这个ip字符串存入字符串缓冲区。
}
}
}
str = new String(sb);//得到新串,排好序的。
System.out.println(str);
//2.2.2.2 8.109.90.30 10.10.10.10 102.49.23.013 192.68.1.254
}
}
//"108","18"...要以字符串中整数的数值大小进行排序的话,
//首先以字符串的长短排序,
//如果字符串的长度相等,再以自然顺序排序。
class IntComparator implements Comparator
{
public int compare(String str1, String str2)
{
int num = new Integer( str1.length() ).compareTo( new Integer(str2.length()) );
if(num==0)
{
return str1.compareTo(str2);
}
else
return num;
}
}
还按照字符串自然顺序,只要让它们每一段都是3位即可。
1,按照每一段需要的最多的0进行补齐,那么每一段就会至少保证有3位。
2,将每一段只保留3位。这样,所有的ip地址都是每一段3位。
import java.util.TreeSet;
class RegexTest3
{
public static void main(String[] args)
{
ipSort();
}
public static void ipSort()
{
String ip = "192.68.1.254 102.49.23.013 10.10.10.10 2.2.2.2 8.109.90.30";
ip = ip.replaceAll("(\\d+)","00$1");//将ip的每一段前面都加两个0
ip = ip.replaceAll("0*(\\d{3})","$1");//将ip的每一段只保留3位
String[] arr = ip.split(" +");//将ip地址按一个或多个空格切开
TreeSet ts = new TreeSet();//将所有ip地址存放到TreeSet集合中,按照字符串自然顺序自动排序。
for(String str : arr)
{
ts.add(str);
}
StringBuffer sb = new StringBuffer();
for(String s : ts)
{
s=s.replaceAll("0*(\\d+)","$1");//将每一段ip前面的零去掉。
sb.append(s+" ");
}
ip = new String(sb);//得到按地址段排序的ip地址串。
System.out.println(ip);
}
}
我自己的方法没有考虑到IP地址的每一段,只按照IP地址的头排序了,有些欠缺。
老师的方法考虑到了IP地址的每一段,如果第一段相同,那么按第二段的大小排,以此类推。
数组的排序方法:
1.Arrays.sort();
2.将数组中的元素存放到TreeSet集合中。如果数组中有重复元素,用方法1.
3.先将数组转成List集合,然后再用Collections.sort();
class RegexTest4
{
public static void main(String[] args)
{
checkMail();
}
public static void checkMail()
{
String mail = "[email protected]";
String mail2 = "[email protected]";
String mail3 = "[email protected]";
/*
邮箱地址的组成:
1.邮箱前缀名可以由小写字母大写字母数字下划线组成,长度6-12位。
2.@
3.域名可以是小写字母大写字母或数字,长度1位到多位。
将 4、5 两个部分封装成组:
4. \\.
5.com或者cn等等,由小写字母或大写字母组成,长度一位到多位。
6.重用以上组,一次或三次。
*/
String regex = "[a-zA-Z0-9_]{6,12}@[a-zA-Z0-9]+(\\.[a-zA-Z]+){1,3}";//较为精确的匹配
System.out.println(mail.matches(regex));
System.out.println(mail2.matches(regex));
System.out.println(mail3.matches(regex));
// \w 单词字符:[a-zA-Z_0-9]
String reg = "\\w+@\\w+(\\.\\w+)+";//相对不太精确的匹配
System.out.println(mail.matches(reg));
System.out.println(mail2.matches(reg));
System.out.println(mail3.matches(reg));
//mail.indexOf("@")!=-1;//只要你的邮箱地址里面有@就行。
}
}
想发垃圾邮件(传播广告),需要获取邮箱地址,使用以下方法:
获取指定文档中的邮件地址。
使用获取功能。Pattern Matcher
import java.io.*;
import java.util.regex.*;
class RegexTest5
{
public static void main(String[] args) throws Exception
{
getMails();
}
/*
获取指定文档中的邮件地址。
使用获取功能。Pattern Matcher
*/
public static void getMails() throws Exception
{
BufferedReader br = new BufferedReader(new FileReader("mail.txt"));
String line = null;
String regex = "\\w+@\\w+(\\.\\w+)+";
Pattern p = Pattern.compile(regex);
while((line=br.readLine())!=null)
{
Matcher m = p.matcher(line);
while(m.find())
{
System.out.println(m.group());
}
}
}
}
把这些地址存到数据库里面去,或者存到一个文件里面去。
以后学 javaWeb 的时候会学到一个 javaMail,用 java 来写一个邮件发送接收程序。
完全可以通过自己写的程序来给 sina 啊、sohu 啊之类的发送邮件。
自己写个邮件服务器,再把这些地址读出来以后,噼里啪啦发这些垃圾邮件就欧了~
刚才我们说了从文档中获取邮箱地址,
现在我们想爬网页,从网页中获取邮箱地址:
我们专门做了一个HTML网页,放到Tomcat服务器的 webapps/myweb/ 文件夹下,双击 bin/startup.bat 开启Tomcat服务器,在浏览器地址栏输入http://192.168.1.101:8080/myweb/mail.html 网址,就可看到网页中的内容。下面我们来获取这个网页中的邮箱地址。【URL、URLConnection】【Pattern、Matcher】
import java.net.*;
import java.io.*;
import java.util.regex.*;
class RegexTest6
{
public static void main(String[] args) throws Exception
{
getMails();
}
public static void getMails() throws Exception
{
URL url = new URL("http://192.168.1.101:8080/myweb/mail.html");
URLConnection conn = url.openConnection();
BufferedReader br = new BufferedReader( new InputStreamReader( conn.getInputStream() ) );
String line = null;
String regex = "\\w+@\\w+(\\.\\w+)+";
Pattern p = Pattern.compile(regex);
while((line=br.readLine())!=null)
{
Matcher m = p.matcher(line);
while(m.find())
{
System.out.println(m.group());
}
}
}
}
把 Tomcat 服务器关了以后,就获取不到了。
------- Windows Phone 7手机开发、.Net培训、期待与您交流! -------