您的位置:首页 > 编程语言 > Java开发

Java与正则表达式

2016-01-03 07:59 260 查看

Java与正则表达式

标签: Java基础

正则


正如
正则
的名字所显示的是描述了一个
规则
, 通过这个规则去
匹配字符串
. 学习正则就是学习正则表达式的
语法规则




正则语法

普通字符

字母, 数字, 汉字, 下划线, 以及没有特殊定义的标点符号都是
普通字符
. 表达式中的普通字符在匹配一个字符串时, 匹配与之相同的一个字符.

转义字符

字符解释
\n
换行符
\t
制表符
\^
\$
\(
\)
\{
\}
\?
\+
\*
|
\\
\[
\]
匹配这些字符本身

标准字符集合

字符匹配
\d
任意一个数字
\w
任意一个字母/数字/下划线
\s
任意一个空格/制表符/换行符等空白字符
.
小数点在内的任意一个字符(除
\n
外)
[\s\S]
匹配
\n
在内的任意一个字符
注意大小写: 大写是取反

自定义字符集合

[]
方括号匹配方式, 能够匹配方括号中的任意一个字符.

表达式解释
[ab5@v]
匹配
a
b
5
@
v
中任意一个
[^ab5@v]
匹配
a
b
5
@
v
之外任意一个
[f-k]
匹配
f-k
之间任意一个字母
[^f-k]
匹配
f-k
之外任意一个
[f-k0-3]
匹配
f-k
0-3
之间任意一个字母
[^f-k0-3]
不匹配
f-k
0-3
之间任意一个字母
注:

正则表达式中的特殊符号, 被包含到
[]
中, 则失去特殊意义, 除了
-
^
之外.

[]
中的
^
表示取反的含义.

[]
中的
-
表示范围的含义

标准字符集合(除小数点外),如果被包含于中括号中,则自定义集合将包含该集合.

[\d.\-+]
将匹配: 数字, 小数点,
-
,
+


量词

量词解释
{n}
表达式重复n次
{m,n}
表达式至少重复m次,最多重复n次
{m,}
表达式至少重复m次
?
匹配表达式0次或者1次
+
表达式至少出现1次,相当于
{1,}
*
表达式不出现或出现任意次,相当于
{0,}
贪婪模式与非贪婪模式

贪婪模式: 匹配字符越多越好,
默认
.

非贪婪模式: 匹配字符越少越好, 需要在量词后再加上一个
?
.

示例

匹配手机号
1[358]\d{9}


匹配邮箱
([\w\-\.]+)@([0-9a-zA-Z\-]+)(\.[a-zA-Z]{2,4}){1,2}


字符边界

零宽匹配: 匹配的不是字符而是位置(符合某种条件的位置),不匹配任何字符.

字符解释
^
与字符串开始的地方匹配
$
与字符串结束的地方匹配
\b
匹配一个单词边界,也就是单词和空格之间的位置
注:
\b
会匹配这样一个位置: 前面的字符与后面的字符不全是
\w


选择符与分组

表达式解释
|
左右两边表达式之间 “或” 关系,匹配左边或右边
()
捕获组
被修饰时,
()
中的表达式可以作为整体被修饰; 取匹配结果时,
()
中的表达式匹配到的内容可以被单独得到; 每一对括号会被分配一个编号(以
(
为准,从左到右: 从1开始)
(?:exp)
非捕获组
一些表达式中, 不得不使用
()
, 但又不需保存
()
中子表达式匹配的内容, 这时可以使用非捕获组来抵消
()
带来的副作用
注: 非捕获组可以用于当处理大量文本时用于优化内存分配.

反引用
\nnn


由上面可知, 捕获组默认被分配了编号, 通过反向引用, 可以对分组已捕获的字符串进行引用

示例

(\w{2})\1
匹配类似
toto
dodo
gogo
这样由一个单词复制而来得到的字符串

(img)\w+\1
匹配前后都是img的字符串

零宽断言(预搜索)

零宽度: 只进行子表达式的匹配, 匹配内容不计入最终的匹配结果.

位置匹配: 判断当前位置的前后字符是否符合指定的条件, 但不保留前后的字符.


正则表达式中, 如果子表达式匹配到得是字符内容, 而非位置, 并被保留到最终的匹配结果中, 那么就认为这个子表达式是
占有字符
的; 如果子表达式匹配的仅仅是位置, 或者匹配的内容并不保存到最终的匹配结果中, 那么就认为这个子表达式是
零宽度
的(占有字符或零宽度, 是针对匹配的内容是否保留到最终结果而言的)



表达式解释
(?=exp)
断言自身出现的位置的
后面能够
匹配表达式exp
(?!exp)
断言自身出现的位置的
后面不能
匹配表达式exp
(?<=exp)
断言自身出现的位置的
前面能够
匹配表达式exp
(?<\!exp)
断言自身出现的位置的
前面不能
匹配表达式exp
示例

[a-z]+(?=ing)
匹配所有以ing结尾的单词, 但ing并不放入字符串

[a-z]+(?=\d+)
匹配所有以数字结尾的单词

[a-z]+(?!\d+)
匹配不以数字结尾的单词

(?<=(href=\"))
匹配以
href="
开头的字符串

Java Pattern与Matcher

java.util.regex
包下提供的
Pattern
Matcher
两个类提供了在Java中的正则支持;

Pattern
对象是正则表达式编译后在内存中的表现形式, 因此, 正则表达式字符串必须先被编译为Pattern对象
Pattern pattern = Pattern.compile("\\w+");
然后再利用该Pattern对象创建对象的Matcher对象
Matcher matcher = pattern.matcher(input);
.

Matcher
对象是一个对
CharSequence
执行匹配操作的正则引擎: 执行匹配所涉及的状态保留在Matcher对象中, 多个Matcher对象可共享同一个Pattern对象.

/**
* Created by jifang on 15/12/15.
*/
public class LearnRegexp {

@Test
public void testSearch() {
String input = "hello1997&&2000";

// 将一个正则表达式编译成Pattern对象
Pattern pattern = Pattern.compile("\\w+");
Matcher matcher = pattern.matcher(input);

// matches尝试将整个字符序列与该模式匹配
System.out.println(matcher.matches());

// reset将matcher中的指针重新定位
matcher.reset();
// find 方法扫描整个字符串, 查找能否找到下一个符合该模式字符串
while (matcher.find()) {
String group = matcher.group();
System.out.println(group);
}
}

/**
* 将所有的数字都替换成'#'
*/
@Test
public void testReplace() {
String input = "1j2h3h4g5o";
Matcher replace = Pattern.compile("[0-9]").matcher(input);
input = replace.replaceAll("#");
System.out.println(input);
}

/**
* 将字符串按数字分割
*/
@Test
public void testSplit() {
String input = "1j24h356h467g589o";
String[] strings = input.split("\\d+");
for (String str : strings) {
System.out.println(str);
}
}
}


由上例可以看到: 其实
String
中某些方法也支持正则表达式, 如split, replace等(Pattern,Matcher与String的其他用法请参考JDK文档).

小实验-抓取网页中所有的超链接

/**
* 模仿网络爬虫, 抓取网站html, 将里面所有的超链接都分析出来
* Created by jifang on 15/12/15.
*/
public class HtmlAnalyzer {

private final String FILE_PATH = "/Users/jifang/save.txt";

@Test
public void client() throws IOException {
String html = downloadHtml("http://www.163.com/", "gbk");
// (?<=(href=\"))(?:[\w.\/\:\?\=\&]+)(?=\")  匹配url的正则
Set<String> urlSet = analyzeHtml(html, "(?<=(href=\\\"))(?:[\\w.\\/\\:\\?\\=\\&]+)(?=\\\")");
saveToFile(urlSet);
System.out.println();
}

private String downloadHtml(String url, String charset) throws IOException {
URL readUrl = new URL(url);
BufferedReader reader = new BufferedReader(new InputStreamReader(readUrl.openStream(), charset));
return CharStreams.toString(reader);
}

private Set<String> analyzeHtml(String html, String regex) {

Set<String> urlSet = new HashSet<>();
// 匹配url的正则表达式
Matcher matcher = Pattern.compile(regex).matcher(html);
while (matcher.find()) {
String group = matcher.group();
urlSet.add(group);
}

return urlSet;
}

private void saveToFile(Set<String> urlSet) throws IOException {
PrintStream printer = new PrintStream(new FileOutputStream(FILE_PATH));
for (String url : urlSet) {
printer.println(url);
}
printer.flush();
printer.close();
}
}


附- 运行上程序需要在pom.xml中添加以下依赖

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>


推荐几个正则验证工具:

Mac端: RegExRX

Win端: RegexBuddy

Web端: 在线正则表达式测试

参考

揭开正则表达式的神秘面纱

Java正则表达式教程
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: