java 正则表达式
介绍
前段时间使用Java的正则表达式做一些字符串匹配的任务,现将学到的正则表达式的知识整理成文。
Java中Spring.class涉及到正则表达式。如Spring.split(), matches(),replaceAll()等方法。
Java中更一般使用正则表达式的方式是利用Pattern.class和Matcher.class,所在package为java.util.regex
Java中正则表达式相关API使用不难掌握,不过重点在于编写合适的正则表达式,尤其是利用字符类和量词的使用。
正则表达式
Java中正则表达式与之前使用的Python是有区别的,区别在于Java对于反斜线(\)处理的不同。
在Python中”\d”表示 匹配一位数字(0-9),而Java中匹配一位数字(0-9),需要的正则表达式为”\\d”。
不过换行符和制表符只需要单反斜线“\n\t”。
字符
给出构造正则表达式的常用字符
字符 | 描述 |
---|---|
B | 指定字符B |
\xhh | 十六进制值为oxhh的字符 |
\uhhhh | 十六进制值为oxhhhh的Unicode字符 |
\t | tab |
\n | 换行 |
\r | 回车 |
\e | 转义 |
字符类
字符类在编写正则表达式起到重要的作用,我们给出一些常用的构造正则表达式的字符类。
字符类 | 描述 |
---|---|
. (小数点) | 任意字符 |
[abc] | [ ] 中括号,包含a,b,c中任意字符 |
[^abc] | [ ]中括号加^, 表示否定,除a,b,c之外的 |
[a-z] | 从a到z的任意字符 |
[a-z&&[hi]] | &&表示交集,即包含h或i |
\s | 空白字符,包含空格,换行,回车,tab,换页 |
\S | 大写为小写的取反,非空白字符,等价于[^\s] |
\d | 数字0-9 |
\D | 非数字,等价于[^0-9] |
\w | 词字符,数字,大小写字母,等价于[0-9a-zA-Z] |
\W | 非词,等价于[^\w] |
逻辑操作符
组合一个或多个表达式,通过逻辑操作符实现。
逻辑操作符 | 描述 |
---|---|
XY | Y跟在X后面,并且XY同时满足 |
X|Y | X或者Y |
(X) | () 小括号表示捕获组(group),可以对group进行处理,尤其是获取其中的内容 |
边界匹配符
针对边界的匹配,给出边界匹配符。
边界匹配符 | 描述 |
---|---|
^ | 一行的开始 |
$ | 一行的结束 |
\b | 词的边界 |
量词
量词描述了一个模式匹配文本的方式,包含
- 贪婪型:量词默认是贪婪的,发现尽可能多的匹配
- 勉强型:通过问号(?)指定,匹配最小的字符数,也称为懒惰型,最少匹配,非贪婪。
- 占有型:通过加号(+)指定,当用于字符串时防止匹配失败时回溯。
贪婪型 | 勉强型 | 占有型 | 描述 |
---|---|---|---|
X? | X?? | X?+ | 匹配0个或1个X |
X* | X*? | X*+ | 匹配0个或多个X |
X+ | X+? | X++ | 匹配1个或多个X |
X{n} | X{n}? | X{n}+ | 恰好匹配n个X |
X{n,} | X{n,}? | X{n,}+ | 至少匹配n个X |
X{n,m} | X{n,m}? | X{n,m}+ | 至少匹配n个X,最多匹配m个X |
正则表达式使用
String
String.class提供了一些方法,如用于切分的split()方法,用于验证是否匹配的matches()方法,用于替换操作的replaceAll方法。简单示例如下:
/**
* String中正则表达式的测试
*
* @throws Exception 异常情况
*/
@Test
public void testStringRegex() throws Exception {
// split
// 结果:[some, examples, of, regex, test]
String query = "some examples of regex test";
String[] parts = query.split(" ");
System.out.println(Arrays.toString(parts));
// matches 整个字符串是否匹配
// 结果:false
String regex = "regex";
boolean isMatched = query.matches(regex);
System.out.println(isMatched);
// replaceAll
// 结果:some <REGEX> examples <REGEX> of <REGEX> regex <REGEX> test
String replaceQuery = " <REGEX> ";
String newQuery = query.replaceAll(" ", replaceQuery);
System.out.println(newQuery);
}
Pattern和Matcher
正则表达式更一般的用法是使用java.util.regex.下的Matcher和Pattern类。
通过Pattern类的静态方法static Pattern.compile() 编译正则表达式,利用Pattern的matcher()方法生产Matcher对象。根据Matcher对象提供的API完成相应的操作。
我们以获取字符串中的电话号码和Html中的标题为例,实现正则表达式的匹配。示例如下:
package com.notepad.thinkingnote.regexes;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Description: 正则表达式
* <p>
* Create: 2018/8/25 21:37
*
* @author Yang Meng([email protected])
*/
public class RegexUtils {
/**
* 获取content中全部的手机号码
*
* @param content 待匹配内容
* @return 电话号码集合
*/
public List<String> getPhoneNumber(String content) {
List<String> phoneNumbers = new ArrayList<>();
Matcher matcher = PHONE_PATTERN.matcher(content);
while (matcher.find()) {
// group=2对应(1\\d{10}), 匹配的值即为手机号码
phoneNumbers.add(matcher.group(2));
}
return phoneNumbers;
}
/**
* 从Html中获取title
*
* @param content a html
* @return the title of a html
*/
public String getHtmlTitle(String content) {
Matcher matcher = TITLE_PATTERN.matcher(content);
return matcher.find()? matcher.group(1):null;
}
/** 手机号码 */
private static final String PHONE_REGEX = "(^|\\D)(1\\d{10})($|\\D)";
private static final Pattern PHONE_PATTERN;
/** html 标题 */
private static final String HTML_TITLE_REGEX = "<title>(.*?)</title>";
private static final Pattern TITLE_PATTERN;
static {
PHONE_PATTERN = Pattern.compile(PHONE_REGEX);
// 不区分大小写
TITLE_PATTERN = Pattern.compile(HTML_TITLE_REGEX, Pattern.CASE_INSENSITIVE);
}
}
构造单测样例如下:
package com.notepad.thinkingnote.regexes;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.*;
/**
* Description: 正则表达式单测
* <p>
* Create: 2018/8/25 21:45
*
* @author Yang Meng([email protected])
*/
public class RegexUtilsTest {
private RegexUtils regexUtils = new RegexUtils();
@Test
public void getPhoneNumber() {
// test 1: 有电话号码
String content = "紧急情况请拨打13845697569";
List<String> phoneNumbers = regexUtils.getPhoneNumber(content);
System.out.println(String.format("[%s] has phone number : [%s]", content, phoneNumbers));
// test 2: 数字12位
content = "紧急情况请拨打138456975690";
phoneNumbers = regexUtils.getPhoneNumber(content);
System.out.println(String.format("[%s] has phone number : [%s]", content, phoneNumbers));
// test 3: 开头不是1
content = "紧急情况请拨打23845697569";
phoneNumbers = regexUtils.getPhoneNumber(content);
System.out.println(String.format("[%s] has phone number : [%s]", content, phoneNumbers));
// test 4: 数字在开头
content = "13845697569紧急情况请拨打";
phoneNumbers = regexUtils.getPhoneNumber(content);
System.out.println(String.format("[%s] has phone number : [%s]", content, phoneNumbers));
}
@Test
public void getHtmlTitle() throws Exception {
// test 1: 正常情况
String content = "<title>学而不厌 诲人不倦 - 第 1 页 - CSDN博客</title>";
String title = regexUtils.getHtmlTitle(content);
System.out.println(String.format("get title [%s] from content: [%s]", title, content));
// test 1: 不区分大小写
content = "<TITLE>学而不厌 诲人不倦 - 第 1 页 - CSDN博客</TITLE>";
title = regexUtils.getHtmlTitle(content);
System.out.println(String.format("get title [%s] from content: [%s]", title, content));
}
}
总结
本文对Java的正则表达式的使用进行了简单的介绍,已经利用Pattern和Matcher进行匹配的样例。当然重要的还是正则表达式的编写,不一定非得很复杂, 重点是适合我们处理的问题。
参考文献
Java编程思想第四版 第十三章
相关阅读
1、Java为纯面向对象的语言。 2、Java语言具有平台无关性。Java为解释性语言,编译器会把Java代码变成“中间字节码”,然后在Java虚
一些Java反编译工具/源代码查看工具的介绍摘要: 有的朋友抱怨他们在使用他们公司的闭源框架时看不到底层的源代码。那么可以尝试
JavaFX学习篇---1、IDEA配置JavaFX开发环境和创建Java
以下操作过程参照官方文档实践,https://www.jetbrains.com/help/idea/preparing-for-javafx-application-development.html 1、安
throws和throw throws:用来声明一个方法可能产生的所有异常,不做任何处理而是将异常往上传,谁调用我我就抛给谁。 用在方法声明后面
BigDecimal a = new BigDecimal (101); BigDecimal b = new BigDecimal (111); //使用compareTo方法比较 //注意:a、b均不能为nul