avatar

正则表达式学习

吐槽

在开始之前请允许我展示一段正则:(?<=\s)\d(?=\s+)|(?<=\s)\d(?!\d+),在我没有学的时候了,我就感觉这NM是一段随便用键盘打的字,这是什么玩意,,,我当时是这么想的,真的没明白这是个什么东西。
但是相信我在学完以后,你一定会真香的!!

什么是正则表达式:

正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。—来自百度百科
其实正则就是用来匹配字符串的,例如we are good,我们需要用正则找出空格,那么我们就需要使用\s+,或者[ ]来进行匹配。

学习正则需要的工具

我怕们学习正则,就要有相应的正则匹配的工具,这里推荐两个:RegexBuddy,MTracer
这两个的下载链接我放在文章末尾,有需要的自己去取一下哈~,
除了工具,我们可以用我们熟悉的语言进行实操,几乎所有的语言都实现了正则表达式,虽然每种语言各不相同,但是大同小异,正则的基本知识都是一样的。

正则中的部分概念:

元字符:

什么是元字符:元字符就是正则里面最基本的操作单元,最基本的元素;

元字符 说明
.(就是一个点) 用来匹配除了换行符以外的任意字符
\w 匹配字母/数字/下划线/汉字
\s 用来匹配任意的空白符,包括空格、制表符、换页符等。与 [ \f\n\r\t\v] 等效。
\d 匹配数字
\b 匹配一个字边界,即字与空格间的位置。例如,”er\b”匹配”never”中的”er”,但不匹配”verb”中的”er”。
^ 匹配一个字符串的开始
$ 匹配一个字符串的结束

元字符的反义:

将元字符大写,就能匹配与之小写相反的字符

元字符 说明
\W 匹配不是字母/数字/下划线/汉字的字符
\S 用来匹配不是空白符的字符
\D 匹配任意的非数字
\B 非字边界匹配。”er\B”匹配”verb”中的”er”,但不匹配”never”中的”er”。
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou以外的字符

字符的转义

例如.是一个元字符,那么我就想去匹配点怎么办?在点前面加\即可

  • \ 为转义字符

正则表达式中的注释

  • #就是正则中的注释,但是最好别用,写出来的已经很难辨认了,你再加注释会被打的。。。
    如果一定要使用注释话,请开启正则中”忽略模式里的空白符”选项

正则表达式中的重复

我们的字符串中肯定会出现重复的字符需要匹配,那么就用到我们的正则中的重复处理

元字符 说明
* 重复0次或者或者更多次
+ 重复一次或更多次
? 重复0次或者一次
{n} 重复n次
{n,} 重复n次或者更多次
{n,m} 重复n次到m次

正则表达式中的分支条件

  • 用 | 把不同的规则分隔开
  • 从左到右的测试每个条件,如果满足了某个分支的话,就不会再去管其他的条件了

字符串中的字符类

  • [] 中括号里面写啥就匹配啥
    [0-9] == \d 匹配0到9的数字
    [a-z0-9A-Z] == \w 匹配0-9,A-Z,a-z的所有字符
    [&?.] 匹配一些标点符号
    [aeiou] 匹配一些字母

正则表达式中分组概念

  • 将子表达式表示成子集
  • 使用() 进行分组
  • 方便对match后的字符串进行划分
  • 分组是可以命名的:(?<groupname> exp) 那么分组的名字就是groupname
  • (?:exp)匹配exp子组,但是不会捕获匹配到的文本也不会给分组分配编号,也就是将其从结果中剔除

贪婪与懒惰

  • 贪婪就是尽可能多的匹配,写法是.*
    给个例子:a.*b (aabab)->aabab,这就是贪婪的匹配结果
  • 懒惰就是尽可能少的匹配 .*?
    匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复
    还是那个例子: a.*?b (aabab) -> aab
元字符 说明
*? 重复任意次,但尽可能少的重复
+? 重复一次或者更多次,但尽可能少的重复
?? 重复0次或者一次,但尽可能少的重复
{n,m}? 重复n次到m次,但尽可能少的重复
{n,}? 重复n次或者更多次,但尽可能少的重复
总之就是在这些后面加一个问号可以进行懒惰匹配。一般没有使用贪婪匹配的情况

正则表达式处理选项

元字符 说明
IgnoreCase(忽略大小写) 匹配时不区分大小写。
Multiline(多行模式) 更改^和$的含义,使它们分别在任意一行的行首和行尾匹配,而不仅仅在整个字符串的开头和结尾匹配。(在此模式下,$的精确含意是:匹配\n之前的位置以及字符串结束前的位置.)
Singleline(单行模式) 更改.的含义,使它与每一个字符匹配(包括换行符\n)。
IgnorePatternWhitespace(忽略空白) 忽略表达式中的非转义空白并启用由#标记的注释。
ExplicitCapture(显式捕获) 仅捕获已被显式命名的组。
这种选项不知道是否在任意的语言中都支持。

反向引用

能看到这里的都是比较有耐心的大哥了,这后面属于一些正则的高阶用法,内容也比较抽象,我用的也不是很好
什么是反向引用呢,我的理解就是重复使用前面定义好的分组,不用自己重新去写了。
例如我写了一个 \b(\w)\b\s+\1\b ,这里的\1的意思就是(\w)。

  • 想要重复指定分组的规则是:
    1、如果子分组没有命名,就按照1,2,3,4这样去找子分组做反向引用
    2、如果子分组做了命名,按照 \K<groupname>的方式做反向引用

零宽断言

  • (?=exp)也叫零宽度正预测先行断言,它断言自身出现的位置的后面能匹配表达式exp。比如\b\w+(?=ing\b),匹配以ing结尾的单词的前面部分(除了ing以外的部分),如查找I’m singing while you’re dancing.时,它会匹配sing和danc。
  • (?<=exp)也叫零宽度正回顾后发断言,它断言自身出现的位置的前面能匹配表达式exp。比如(?<=\bre)\w+\b会匹配以re开头的单词的后半部分(除了re以外的部分),例如在查找reading a book时,它匹配ading。
    这里我很想吐槽一句,其实就是不占位置的前后匹配,但是这样取名字真的很难明白是啥意思。。反正我是理解了很久才明白是怎么回事

负向零宽断言

其实和零宽断言相反,就是匹配不占位的不是某种条件的情况

  • 零宽度负预测先行断言(?!exp),断言此位置的后面不能匹配表达式exp。例如:\d{3}(?!\d)匹配三位数字,而且这三位数字的后面不能是数字;\b((?!abc)\w)+\b匹配不包含连续字符串abc的单词。
  • 零宽度负回顾后发断言来断言此位置的前面不能匹配表达式exp:(?<![a-z])\d{7}匹配前面不是小写字母的七位数字。

还有个玩意叫平衡组/递归匹配

这个玩意好像只有.net有,这里不打算介绍了,我也没有仔细的去看,大家想学自己去百度把。。

至此正则的大部分内容已经说完了,后面就是实战部分。

常用的正则表达式:

表达式 说明
^[0-9]*$ 数字
^\d{n}$ n位数字
^\d{n,}$ 至少n位数字
^[\u4e00-\u9fa5]{0,}$ 汉字
^\w+([-+.]\w+)*@\w+([-.]\w+)*.\w+([-.]\w+)*$ Email地址
[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.? 域名
这个我会持续补充,这里不做太多的介绍。

java如何写正则

Pattern类

Java提供了java.util.regex.Pattern 类来创建正则表达式对象

  • public static boolean matches(regex, str) // 用来判断str是否匹配regex,或者说用来判断str是否符合regex的要求
public class Main {
public static void main(String[] args) {
String rexge = "\\w+";
String str = "123e";
System.out.println(Pattern.matches(rexge,str));
}
}
//返回一个true

元字符的用法

  • Java代码中的 \ 只表示正则中的 \

重复匹配

public class Main {
public static void main(String[] args) {
String rexge = "\\w*";
String str = "123e";
System.out.println(Pattern.matches(rexge,str));
}
}//与元字符的使用相同

其他正则匹配的使用方式与元字符的类似

Matcher类

public class Main {
public static void main(String[] args) {
//打印出一个字符串里面的所有的qq邮箱
String regex = "[1-9][0-9]{4,}@qq.com";// qq邮箱的正则表达式写法
String str = "xx12345@qq.comabc123456@qq.commm1234567@qq.com";

Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);

while (matcher.find()) {
String group = matcher.group();
System.out.println(group);
}
}
}

String也支持正则表达式

  • String的方法中参数为regex的都是支持正则的。
  • String newStr = str.replaceAll(regex, replacement);
  • String[] newStrs = str.split(regex);//使用regex作为分隔符切分str
  • boolean match = str.matches(regex);// 等同于Pattern.matches(regex, str)

给大家推荐几个教程

练习用到的工具:

文章作者: zenshin
文章链接: https://zlh.giserhub.com/2020/03/07/cl35o0mpz0023p4tg1s7n79i1/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 zenshin's blog
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论