开发者社区> 翡青> 正文

Java与正则表达式

简介: Java与正则表达式 标签: Java基础 正则 正如正则的名字所显示的是描述了一个规则, 通过这个规则去匹配字符串.
+关注继续查看

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-k0-3之间任意一个字母
[^f-k0-3] 不匹配f-k0-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包下提供的PatternMatcher两个类提供了在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>

推荐几个正则验证工具:


参考

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
「如何优雅的不写注释🌿」每个工程师都要不断追求的漫漫长路
「如何优雅的不写注释🌿」每个工程师都要不断追求的漫漫长路
5 0
组件构建原则(一):组件
组件构建原则(一):组件
3 0
组件构建原则(二):组件聚合
组件构建原则(二):组件聚合
4 0
TypeScript(二)使用Webpack搭建环境
学习任何的开发,我们都需要对应的环境:包括TypeScript的编译环境和开发工具。这个章节里面,我们就来完成它们的搭建,后续就可以愉快的来写TypeScript代码了。
6 0
dex加载后导入类报错
牙叔教程 简单易懂
8 0
TypeScript(三)定义变量和数据类型
这个章节我们来学习如何在TypeScript中定义变量,以及JavaScript类型在TypeScript中的变化以及TypeScript中新增的类型
5 0
你不必担心Dart的垃圾回收器(译)
在学习Flutter的过程中,我们知道Widget只是最终渲染对象(RenderObject)的配置文件,它会在build的时候频繁的销毁和创建,那么,我们不需要担心他的创建和销毁带来的性能问题吗? 其实大可不必,因为Dart针对Flutter的Widget的创建和销毁专门做过优化,这也是Flutter在多种语言中选择Dart的一个重要因素,甚至我们还可以刻意利用这一点。 下面这篇文章解析了Dart的GC(Garbage Collector),对它做了个翻译以及部分内容的解析,包括一些排版,有不对的地方大家多多指正。 原文地址:https://medium.com/flutter/flu
2 0
Spring MVC获取HTTP请求头的两种方式小结
这篇文章主要介绍了Spring MVC获取HTTP请求头的两种方式小结,帮助大家更好的理解和使用Spring MVC,感兴趣的朋友可以了解下
5 0
从 Object.assign 开始了解ES2015
ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准。因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015。也就是说,ES6就是ES2015。本文着重介绍ES2015新增内容之一:Object.assign。在文章最后也介绍ECMAScript的发展历程。
1 0
+关注
翡青
阿里巴巴高级研发工程师
211
文章
34
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载