通俗易懂的正则表达式入门及应用

正则表达式(RegularExpression),常用于对大段文本的处理,常用操作有:匹配、提取、替换。

第一个例子

比如有一个电话号码:13132314693

这个规则可以描述为:

  • 以1开头
  • 共11位数字
  • 必须为0-9的数字

用正则表达式来描述可以写成:1[0-9]{10}

其中:1表示1开头,[0-9]表示(0到9)的数,{10}表示出现10次。合起来就是,1开头,0-9的数字出现10次。

重复次数匹配{}

比如有以下3个字符串:

  1. Huawei
  2. Huaawei
  3. Huaaawei

这3个字符串可以用正则描述为:Hua{1,3}wei

其中:{1,3}表示仅挨着的字符‘a’重复出现1次到3次,最少1次,最多3次,都是能够匹配得上的。

其他用法

扩展用法:

  • {m,n}  :表示出现最少m次,最多n次
  • {m,}  :表示最少m次,最多不限量
  • {,n}  :表示最少不限量,最多n次
  • {m}  :表示刚好出现m次

还有几个关键字符:

  • *  :表示0次,1次,或者N次,相当于{0,}
  • + :表示1次,或N次,相当于{1,}
  • ? :表示0次,或1次,相当于{0,1}

例如:Hua+wei 相当于 Hua{1,}wei

 

简单使用-匹配:JAVA代码如下

package com.example.editor.controller;

import java.util.regex.Pattern;

public class Test3
{
	public static void main(String[] args)
	{
		String content = "Huawei";
		String regex = "Hua+wei";	// “Hua*wei”  /  ”Hua?wei”
		// 传入:正则式,要匹配的字符串
		boolean isMatch = Pattern.matches(regex, content);
		if(isMatch) {
			System.out.println("匹配");
		}
		else {
			System.out.println("不匹配");
		}
	}
}

字符区间匹配[]

有以下字符串:

用正则表达式来描述可以写成:梁[瑞小微]博

其中:中括号[]表示区间内任意一个字符,表示以梁字开头,表示以博字结尾,中间表示选项,选项只能匹配一个,如:梁[瑞小]博 就是不匹配的了。

其他用法

区间匹配[]的其他用法:

  • [a-zA-Z]  :所有的字母,大写+小写
  • [0-9]  :0-9的数字
  • [0-9a-zA-Z_]  :数字+小写字母+大写字母+下划线
  • [^abc]  :除abc三个字母以外都匹配,括号里面的以^开头,表示"非"。
  • [0-3a-fA-F]  :表示0,1,2,3,a,b,c,d,e,f,A,B,C,D,E,F
  • [0-3abcdefABCDEF]  :表示意义同  [0-3a-fA-F]

小练习

一般来说,小括号[]跟大括号{}是连用的,例如,要求用户设定一个6-12位的密码,密码可以是数字、字母、下划线。

用正则表达式描述为:[0-9a-zA-Z_]{6,12}

简单应用-匹配:JAVA代码如下

public static boolean checkInput(String passWord)
{
	// 用户注册的时候,检查用户设置的密码是不是符合规则
	// 假设我们规定要求用户设定一个6到12位数的密码,密码可以是数字、字母、下划线
	String regex = "[0-9a-zA-Z_]{6,12}";
	return Pattern.matches(regex, passWord);
}

分组()

有以下字符串:

  • ChinaGreat
  • ChinanaGreat
  • ChinananaGreat

用正则表示式可以表示为:Chi(na)+Great

其中:'+'号我们上文说过,表示出现1次到N次,也可以写成:Chi(na){1,}Great ,其中的“(na)”表示na这两个字符作为一个组出现,是一体的。

字符的转义

例如我们需要表示完整的手机号,例如

  • +86-13244534545
  • +86-13245453456
  • +86-13287657674

    上面的三个手机号中,+86表示区号,但是在正则表达式看来,+,-都是关键字,并不是普通字符,那我们要怎么来描述如上的三个手机号字符串呢?

    常规思想:+86-1[0-9]{10},表示"+86-1"开头,0-9的数字有10位。

    但是我们发现在程序执行中报错了,原因是+号表示匹配前面紧挨着的字符0-N次,但是前面并没有字符,所以这样子是不行的。

 

    在正则表达式中,如果想要把特殊字符作为普通字符串使用,需要用"\"进行转义。

    例如:\+86-1[0-9]{10}   : +号这里是作为普通字符使用,而不是关键字,所以用“\+”代替“+”。

    写成JAVA代码则为:\\+86-1[0-9]{10}   : 注意,此处有两个"\",代表此处有两层转义,一层是正则表达式对特殊字符的转义,另一层是JAVA代码对字符串的转义。

需要转义的字符

正则表达式需要转义的字符:

*    +    ?    {}    []    ()    .    ^    $    \

常见的特殊字符

  • .      :表示任意一个字符
  • \d      :表示数字,相当于[0-9]
  • \D      :表示非数字,相当于[^0-9]
  • \s      :表示空白字符,相当于[\t\n\x0B\f\r]
  • \S      :表示非空白字符,相当于[^\s]
  • \w      :表示字符,相当于[a-zA-Z0-9_]
  • \W      :表示非字符,相当于[^\w]
  • \b      :匹配单词的开始或结束的位置
  • \B      :匹配不是单词的开始或结束的位置
  • $      :匹配字符串的结束
  • |      :表示分支条件,  0\d{2}-\d{8}|0\d{3}-\d{7} :这个表达式能匹配两种以连字号分隔的电话号码:第一种是三位区号,8位本地号的号码(如010-12387456),第二种是四位区号,7位本地号的号码(如0376-2255435)。

例如:

  • 1[0-9]{10} 与 1\d{10} 的效果是一样的
  • <meta charset='UTF-8'> 可以描述为 <meta\s+charset=.*?>
  • 2249508163lonng@qq.com 描述为 [\w@.]+  , 在JAVA中表示为:String regex = "[\\w@.]+" ; 注意,中括号里面的'.'没有歧义,无需转义。

实际应用

匹配

看上面的“重复次数匹配”部分

提取

根据匹配到的内容来提取

简单提取

应用示例-提取-简单提取:JAVA代码如下

public class Test2
{

	public static void main(String[] args)
	{
		/**
		使用正则表达式的提取,比如,在HTML中的图片标签格式为
		<img src=’url’>
		现在给出一段HTML文本,要求从中提取出所有<img>标签的内容
		*/
		
		// 准备文本
		String content = "更多图片<img src='1.jpg'> <br>"
				+ "示例2 <img src='2.jpg'> <br>"
				+ "示例3 <img src='3.jpg'> <br>嘻嘻嘻";
		
		// 正则表达式
		String regex = "<img.*>";	// <img.*?> 这里要加一个?号,表示非贪心模式,+和*为贪心,?为非贪心
		
		// 传入一个正则表达式,得到一个pattern对象
		Pattern pattern = Pattern.compile(regex);
		// 调用matcher方法传入文本得到matcher对象
		Matcher m = pattern.matcher(content);
		// m.find()方法如果匹配到了就返回true
		while (m.find())
		{
			System.out.println("**匹配:" + m.group(0));	// group(0)指全部
		}
		
		/*	
			贪心跟非贪心的区别,因为<img.*>中.表示任意字符,*表示任意个字符,所以贪心会找到最后一个">"才算完。
			
				<img.*?>输出:
				**匹配:<img src='1.jpg'>
				**匹配:<img src='2.jpg'>
				**匹配:<img src='3.jpg'>
		 */
		
		/*	
				<img.*>输出:
				**匹配:<img src='1.jpg'> <br>示例2 <img src='2.jpg'> <br>示例3 <img src='3.jpg'> <br>
		*/

	}

}

分组提取

应用示例-提取-分组提取1:JAVA代码如下

public class Test
{

	public static void main(String[] args)
	{
		String content = " <img src=\"/image/16056333394802.png\" width=\"100\" />"
						+ "<img src=\"/image/16056333479373.png\" width=\"100\" />\r\n"
						+ "<img src=\"/image/16056333479373.png\" width=\"100\" />\r\n"
						+ "<img src=\"/image/16056333479373.png\" width=\"100\" />\r\n" ;
		// 提取<img>标签中的url参数
		List<String> imaList = getImgStrTest(content);
		System.out.println(imaList.toString());
		
		System.out.println("Exit");
	}
	
	// <img>标签中的url参数提取
	public static List<String> getImgStrTest(String htmlStr)
	{
		List<String> list = new ArrayList<>();
		String regex = "<img.*?src=['\"]{1}/(.*?)['\"]{1}.*?>";
		Pattern pattern = Pattern.compile(regex);
		Matcher m = pattern.matcher(htmlStr);
		while (m.find())
		{
			// group(1)表示提取第一个分组里面的内容,即中(.*?)的内容,如果后面还有多个分组,那么就group(2)-3-4..
			list.add(m.group(1));
		}
		return list;
	}
}

程序输出:

[image/16056333394802.png, image/16056333479373.png, image/16056333479373.png, image/16056333479373.png]

应用示例-提取-分组提取2:JAVA代码如下

public class Test
{

	public static void main(String[] args)
	{
		String content = " <img src=\"/image/16056333394802.png\" width=\"100\" />"
						+ "<img src=\"/image/16056333479373.png\" width=\"100\" />\r\n"
						+ "<img src=\"/image/16056333479373.png\" width=\"100\" />\r\n"
						+ "<img src=\"/image/16056333479373.png\" width=\"100\" />\r\n" ;
		
		List<String> imaList = getImgStr(content);
		System.out.println(imaList.toString());
		
		System.out.println("Exit");
	}
	
	public static List<String> getImgStr(String htmlStr)
	{
		List<String> list = new ArrayList<>();
		String img = "";
		// String regEx_img = "<img.*src=(.*?)[^>]*?>"; //图片链接地址
		String regEx_img = "<img.*src\\s*=\\s*(.*?)[^>]*?>";
		Pattern p_image = Pattern.compile(regEx_img, Pattern.CASE_INSENSITIVE);	// 不分大小写匹配
		Matcher m_image = p_image.matcher(htmlStr);
		while (m_image.find())
		{
			// 得到<img />标签
			img = m_image.group();
			// 匹配<img>中的src数据
			Matcher m = Pattern.compile("src\\s*=\\s*\"?(.*?)(\"|>|\\s+)").matcher(img);
			while (m.find()){
				list.add(m.group(1));
			}
		}
		return list;
	}
}

程序输出:

[/image/16056333394802.png, /image/16056333479373.png, /image/16056333479373.png, /image/16056333479373.png]

替换

应用示例-替换-简单替换-把正则匹配到的所有字段全部统一替换

public class Test
{
	public static void main(String[] args)
	{
		String content = "aaaabXaaabMaaaaaaaaabL";
		String str = replaceImgTag1(content);
		System.out.println(str);
		
		System.out.println("Exit");
	}
	
	// 文本替换
	public static String replaceImgTag1(String str)
	{
		String regex = "a*b";
		Pattern pattern = Pattern.compile(regex);
		Matcher m = pattern.matcher(str);		
		// 用*号代替匹配的字符
		return m.replaceAll("*");
	}
}

程序输出: 

*X*M*L

应用示例-替换-复杂替换-把正则匹配到的分开替换,各换各的

public class Test
{
	public static void main(String[] args)
	{
		String content = "1:xxxxxx。" 
				+ "2:XXXXXXXXXXX。"
				+ "3:yyyyyyyyyyy。"
				+ "4";
		List<String> strList = new ArrayList<String>();
		strList.add("第一条");
		strList.add("第二条");
		strList.add("第三条");
		strList.add("第四条");
		
		String str = replace(content, strList);
		System.out.println(str);
		
		System.out.println("Exit");
	}
	
	public static String replace(String html, List<String> strList)
	{
		String regex = "\\d{1}";
		Pattern pattern = Pattern.compile(regex);
		Matcher m = pattern.matcher(html);
		StringBuffer sb = new StringBuffer(); 
		int i = 0;
		while( m.find())	        
		{     	
			// 根据检索到上下文本,作相应的替换
			m.appendReplacement(sb, strList.get(i));
			i ++;
			if(i == strList.size()) i = 0;
		}
		return sb.toString();
	}
	
}

程序输出:

第一条:xxxxxx。第二条:XXXXXXXXXXX。第三条:yyyyyyyyyyy。第四条

应用示例-替换-按分组替换-把正则匹配到的分组里面的值替换

public class Test
{
	public static void main(String[] args)
	{
		String content = " <img src=\"/image/16056333394802.png\" width=\"100\" />"
				+ "<img src=\"/image/16056333479373.png\" width=\"100\" />\r\n"
				+ "<img src=\"/image/16056333479373.png\" width=\"100\" />\r\n"
				+ "<img src=\"/image/16056333479373.png\" width=\"100\" />\r\n" ;;
		List<String> strList = new ArrayList<String>();
		strList.add("liangruibo/22222.png");
		strList.add("liangruibo/33333.png");
		strList.add("liangruibo/44444.png");
		strList.add("liangruibo/55555.png");
		
		String str = regReplaceImage(content, strList);
		System.out.println(str);
		
		System.out.println("Exit");
	}
	
	public static String regReplaceImage(String content, List<String> picList)
	{
		String pattern="<img.*?src=['\"]{1}([^l].*?)['\"]{1}.*?>";
        StringBuffer operatorStr = new StringBuffer(content);
        Pattern p = Pattern.compile(pattern);
        Matcher m = p.matcher(content);
        int i = 0;
        while(m.find()) {
            operatorStr.replace(m.start(1), m.end(1), picList.get(i));
            m = p.matcher(operatorStr);
            i ++;
            if(i == picList.size())
            	i = 0;
        }
        return operatorStr.toString();
    }
}

程序输出:

<img src="liangruibo/22222.png" width="100" />
<img src="liangruibo/33333.png" width="100" />
<img src="liangruibo/44444.png" width="100" />
<img src="liangruibo/55555.png" width="100" />

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值