正则表达式
一、正则表达式
正则表达式:符合一定规则的表达式。
作用:用于专门操作字符串。
特点:用一些特定的符号来表示一些代码操作。简化代码书写。学习正则表达式,就是在学习一些特殊符号的使用。
练习:对QQ号码进行校验。
要求:5~15位,0不能开头,只能是数字。
class Demo
{
public static void main(String []args) throws Exception{
String QQ = "63224d5";
if(QQ.length()>=5&&QQ.length()<=15){
if(QQ.charAt(0)!='0'){
char[] chs = QQ.toCharArray();
boolean flag = true;
for(int x=0;x<chs.length;x++){
if(!(chs[x]>='0'&&chs[x]<='9')){
flag = false;
break;
}
}
if(flag){
System.out.println(QQ);
}
else
System.out.println("非法字符");
}
else{
System.out.println("不能以0开头");
}
}
else{
System.out.println("号码长度错误");
}
}
}
分析:这种方式使用了String类中的方法进行组合,完成了需求,但是代码过于复杂。
使用正则表达式:
boolean matches(String regex)
告知此字符串是否匹配给定的正则表达式。
例:
class Demo
{
public static void main(String []args) throws Exception{
String QQ = "21445";
String regex = "[1-9][0-9]{4,14}";
if(QQ.matches(regex)){
System.out.println(QQ);
}
else
System.out.println("不合法");
}
}
正则表达式:
字符
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')
\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]
POSIX 字符类(仅 US-ASCII)
\p{Lower} 小写字母字符:[a-z]
\p{Upper} 大写字母字符:[A-Z]
\p{ASCII} 所有 ASCII:[\x00-\x7F]
\p{Alpha} 字母字符:[\p{Lower}\p{Upper}]
\p{Digit} 十进制数字:[0-9]
\p{Alnum} 字母数字字符:[\p{Alpha}\p{Digit}]
\p{Punct} 标点符号:!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
\p{Graph} 可见字符:[\p{Alnum}\p{Punct}]
\p{Print} 可打印字符:[\p{Graph}\x20]
\p{Blank} 空格或制表符:[ \t]
\p{Cntrl} 控制字符:[\x00-\x1F\x7F]
\p{XDigit} 十六进制数字:[0-9a-fA-F]
\p{Space} 空白字符:[ \t\n\x0B\f\r]
java.lang.Character 类(简单的 java 字符类型)
\p{javaLowerCase} 等效于 java.lang.Character.isLowerCase()
\p{javaUpperCase} 等效于 java.lang.Character.isUpperCase()
\p{javaWhitespace} 等效于 java.lang.Character.isWhitespace()
\p{javaMirrored} 等效于 java.lang.Character.isMirrored()
Unicode 块和类别的类
\p{InGreek} Greek 块(简单块)中的字符
\p{Lu} 大写字母(简单类别)
\p{Sc} 货币符号
\P{InGreek} 所有字符,Greek 块中的除外(否定)
[\p{L}&&[^\p{Lu}]] 所有字母,大写字母除外(减去)
边界匹配器
^ 行的开头
$ 行的结尾
\b 单词边界
\B 非单词边界
\A 输入的开头
\G 上一个匹配的结尾
\Z 输入的结尾,仅用于最后的结束符(如果有的话)
\z 输入的结尾
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 次
Logical 运算符
XY X 后跟 Y
X|Y X 或 Y
(X) X,作为捕获组
Back 引用
\n 任何匹配的 nth 捕获组
引用
\ Nothing,但是引用以下字符
\Q Nothing,但是引用所有字符,直到 \E
\E Nothing,但是结束从 \Q 开始的引用
特殊构造(非捕获)
(?:X) X,作为非捕获组
(?idmsux-idmsux) Nothing,但是将匹配标志i d m s u x on - off
(?idmsux-idmsux:X) X,作为带有给定标志 i d m s u x on - off
的非捕获组 (?=X) X,通过零宽度的正 lookahead
(?!X) X,通过零宽度的负 lookahead
(?<=X) X,通过零宽度的正 lookbehind
(?<!X) X,通过零宽度的负 lookbehind
(?>X) X,作为独立的非捕获组
常见操作:1.匹配:matches方法,用规则匹配整个字符串,只有不符合规则,匹配结束,返回false。
练习:手机号判断。只有13XXX,15XXX,18XXX。
class Demo
{
public static void main(String []args) throws Exception{
String tel = "15508888888";
String regex = "[1][358][0-9]{9}";
if(tel.matches(regex))
System.out.println("ok");
else
System.out.println("sorry");
}
}
2.切割:split方法。
class Demo
{
public static void main(String []args) throws Exception{
String name = "zhangsan lisi wangwu";
String regex = " +";
String[] arr= name.split(regex);
for(String s : arr){
System.out.println(s);
}
}
}
注:“.”是特殊符号,“\.”又是正则表达式,所以要想表示一个“.”符号必须转义——“\\.”。“\”也是特殊字符,所以表示一个“\”也必须转义——“\\”。
例:
class Demo
{
public static void main(String []args) throws Exception{
String name = "Demo.java";
String regex = "\\.";
String[] arr= name.split(regex);
for(String s : arr){
System.out.println(s);
}
}
}
例:
class Demo
{
public static void main(String []args) throws Exception{
String name = "c:\\abc\\a.txt";
String regex = "\\\\";//一个"\"只转义一个"\"
String[] arr= name.split(regex);
for(String s : arr){
System.out.println(s);
}
}
}
练习:切叠词。
为了让规则结果被重用,可以将规则封装成一个组,用“()”完成。组的出现都有编号,从1开始。要使用已有的组,可以通过“\n”(n代表组编号)的形式获取。
class Demo
{
public static void main(String []args) throws Exception{
String name = "dsadakkkhdeezooo";
String regex = "(.)\\1+";
String[] arr= name.split(regex);
for(String s : arr){
System.out.println(s);
}
}
}
3.替换:replaceAll方法。
练习:将字符串中出现5次的数字换成“#”号。
class Demo
{
public static void main(String []args) throws Exception{
String str = "asfasf46366ffaso9qw899";
String regex = "\\d{5,}";
str = str.replaceAll(regex,"#");
System.out.println(str);
}
}
练习:将叠词替换成“#”号。
class Demo
{
public static void main(String []args) throws Exception{
String str = "wkkidssrvjjjyt";
System.out.println(str);
String regex = "(.)\\1+";
str = str.replaceAll(regex,"#");
System.out.println(str);
}
}
练习:将叠词替换成单个字符。“$”获取组里的元素。
class Demo
{
public static void main(String []args) throws Exception{
String str = "wkkidssrvjjjyt";
System.out.println(str);
String regex = "(.)\\1+";
str = str.replaceAll(regex,"$1");
System.out.println(str);
}
}
4.获取:将字符串中符合规则的字串取出。
操作步骤:
1.将正则表达式封装成对象。
2.让正则对象和要操作的字符串相关联。
3.关联后获取正则匹配引擎。
4.通过引擎对符合规则的字串进行操作,比如取出。
java.util.regex:正则包。
Pattern:正则对象。
练习:将不超过三个字母的单词取出。
import java.util.regex.*;
class Demo
{
public static void main(String []args) throws Exception{
String str = "ming tian jiu yao fang jia le,da jia.";
//"\b"为单词边界匹配器
String regex = "\\b[a-z]{1,3}\\b";
//将规则封装成对象
Pattern p = Pattern.compile(regex);
//让正则对象和要作用的字符串相关联,获取匹配器对象。Matcher称为引擎或匹配器。
Matcher m = p.matcher(str);
while(m.find()){
System.out.println(m.group());
}
}
}
其实,String类中的matches方法,用的就是Pattern和Matcher对象来完成的,只不过被String的方法封装后,用起来较为简单,但是功能单一。
容易疏忽的地方:
import java.util.regex.*;
class Demo
{
public static void main(String []args) throws Exception{
String str = "jiu yao fang jia le,da jia.";
String regex = "\\b[a-z]{1,3}\\b";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(str);
System.out.println(m.matches());
while(m.find()){
System.out.println(m.group());
}
}
}
jiu也满足了条件,可是却没有打印出来,
这是神马呢?

答:和Iterator的hasNext一样,m.matches();已经将指针(索引)往后移了一位。所以也就没有打印jiu。
练习:将下列字符串转成:我要学编程。
我我.....我我........我要.......要要......要要.......学学.....学学......编编.....程....程程.....程.....程

思考方式:
1.如果只想知道该字符串是对是错,可以使用匹配。
2.想要将已有的字符串变成另一个字符串,可以使用替换。
3.想要按照指定的方式变成多个字符串,可以使用切割。
4.想要拿到符合要求的字符串字串,可以使用获取。
思路:
1.可以先将“.”去掉。
2.再将多个重复内容变成单个内容。
class Demo
{
public static void main(String []args) throws Exception{
String str = "我我.....我我........我要.......要要......要要.......学学.....学学......编编.....程....程程.....程.....程";
System.out.println(str);
str = str.replaceAll("\\.+","");
System.out.println(str);
str = str.replaceAll("(.)\\1+","$1");
System.out.println(str);
}
}
练习:将ip地址进行顺序的排序。
192.168.1.254 102.49.23.1310.10.10.10 2.2.2.2 8.109.90.30
思路:
1.按照每一段需要的最多的“0”进行补齐,那么每一段就会至少保证有3位。
2.将每一段只保留3位,这样,所有的ip地址都是每一段3位。
import java.util.*;
class Demo
{
public static void main(String []args) throws Exception{
String str = "192.168.1.254 102.49.23.13 10.10.10.10 2.2.2.2 8.109.90.30";
str = str.replaceAll("(\\d+)","00$1");
str = str.replaceAll("0*(\\d{3})","$1");
String[] arr = str.split(" ");
TreeSet<String> ts = new TreeSet<String>();
for(String s : arr){
ts.add(s);
}
for(String s : ts){
s = s.replaceAll("0*(\\d+)","$1");
System.out.println(s);
}
}
}
练习:对邮件地址进行校验。
import java.util.*;
class Demo
{
public static void main(String []args) throws Exception{
String mail = "abc123@sina.com";
String reg = "[a-zA-Z0-9_]+@[a-zA-Z0-9_]+(\\.[a-zA-Z]+)+";
System.out.println(mail.matches(reg));
}
}
常见校验格式:
[a-zA-Z0-9_]+@[a-zA-Z0-9_]+(\\.[a-zA-Z]+)+(较为精确),简写:[\\w_]+@[\\w_]+(\\.[\\D&&\\w]+)+。
练习:网页爬虫
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import java.util.regex.*;
class DemoIE
{
private Frame f;
private TextField tf;
private Button b;
private TextArea ta;
private Dialog d;
private Label l;
DemoIE(){
init();
}
public void init(){
f = new Frame("MyIE");
f.setBounds(400,150,700,500);
f.setLayout(new FlowLayout());
tf = new TextField(70);
f.add(tf);
b = new Button("转到");
f.add(b);
ta = new TextArea();
ta.setRows(26);
ta.setColumns(78);
f.add(ta);
d = new Dialog(f,"提示");
d.setBounds(500,300,300,100);
d.setLayout(new FlowLayout());
f.setVisible(true);
myEvent();
}
public void myEvent(){
f.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
tf.addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e){
if(e.getKeyCode()==KeyEvent.VK_ENTER){
load();
}
}
});
b.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
load();
}
});
}
public void load(){
ta.setText("");
try{
String str = tf.getText();
//URL url = new URL(new String(str));
//String host = url.getHost();
//int port = url.getPort();
//if(port == -1)
// port = 80;
//String file = url.getFile();
if(!str.startsWith("http://"))
str = "http://"+str;
URL url = new URL(str);//"http://"+host+":"+port+"//"+file);
String host = url.getHost();
int port = url.getPort();
if(port == -1)
port = 80;
String file = url.getFile();
url = new URL("http://"+host+":"+port+"//"+file);
URLConnection conn = url.openConnection();
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line = null;
while((line = br.readLine())!=null){
Pattern p = Pattern.compile("[\\w_]+@[\\w_]+(\\.[\\D&&\\w]+)+");
Matcher m = p.matcher(line);
while(m.find()){
ta.append(m.group()+"\r\n");
}
}
}
catch(Exception e){
System.out.println("nono");
}
}
public void showDia(String info){
l.setText(info);
d.setVisible(true);
}
public static void main(String []args){
new DemoIE();
}
}