Java里正则表达式(包括一些高级用法)

原文:https://www.cnblogs.com/tomcatandjerry/p/13364566.html
博主没有排版,我自己排了下,如有侵权请联系我

字符种类

部分使用频率几乎为 0 的这里不会提及(比如 \x 之流)

普通

含义助记
\s非空白space
\s空白
\d数字digit
\D非数字
[]自定义字符种类可使用 ^ | && 随意组合

特别

含义助记
\h横向字符horizontal
\h非横向字符
\v纵向字符(比如说换行符)vertical
\V非纵向字符
\w单词字符(包括 - _)word
\W非单词字符
\p{XXX}POSIX,这个并不常用,在有些时候会方便,Character 有很多 is开头的方法,将方法名中的is替换为Java可直接使用进行字符匹配:\p{javaLowerCase}posix
\Q字符转义开始符
\E字符转义结束符,这两个符号之间的内容全部按照字面量处理,里面是所有字符都不会有什么含义,比如 . 就是 .,\s 必须匹配\s,而不是匹配空白。

量词

含义助记
?0个或者1个
*0个或多个
+1个或多个
{m}m个
{m,n}介于m~n个之间

?修饰在量词之后,表尽可能少的匹配!

边界

普通

含义助记
^字符开始位置
$字符结束位置

特别

含义助记
\b单词边界,单词的最前面和最后面
\B非字符串边界

下面的内容普通人基本上就已经不管了!

分组捕获

正则表达式中,每出现一对括号就是新建了个新的组。比如:(\\w+)|(\\d+)

正则表达式的组可以用使用索引进行引用,形式为:$index

$0 默认指向原来的全部字符

然后索引递增规律如下:

((a)|(bc))

$1 指向 ((a)|(bc)) 匹配的内容

$2 指向 (a) 匹配的内容

$3 指向 (bc) 匹配的内容

然而当正则复杂之后,改动将会对索引有较大影响,也不方便计算索引,此时,你可以为组制定名称:

比如匹配字符串:a=123,b=456中间的键值,使用索引,需要写成:(\\w+)=(\\S+),然后使用$1指向 key,使用 $2 指向 value。

我们可以将正则改为:(?<key>\\w+)=(?<value>\\S+),上述表达式使用 ?<name> 的形式在正则中为组定义名称。

引用分组

在 Java 中,你可以在两种地方使用引用:

  • 正则表达式中

匹配 xxx-xxx 字符 - 两边的内容相同,使用索引引用前面的组(\\index):

(\\w+)-\\1

使用名字引用前面的组:

(?<content>\\w+)-\\k<content>
  • 在 Java 的字符串替换中

Markdown 中的字符串转为斜线的html:

"*name*".replaceAll("\\*(?<content>\\w+)\\*", "<em>$1</em>")
"*name*".replaceAll("\\*(?<content>\\w+)\\*", "<em>${content}</em>")

模式

你可以在构造 Pattern时设定模式:

Pattern.compile("abc", Pattern.CASE_INSENSITIVE)

模式可以自行到 Pattern下查看,这里只说使用方式,在组开头使用 ?flags:的方式声明模式,比如:

匹配单词,不区分大小写

(?i:\\w+)

记住i(忽略大小写)、s(. 匹配全部字符)即可,其他基本不用。

前瞻后顾

前瞻后顾,是正则表达式中的高级技巧,主要有5种:

注意:虽然这货也有括号,但是这货只算个条件,并不会捕获任何内容,也不会影响索引

前瞻

前瞻中不带<,并且只影响前面的表达式,意思就是偷偷往前看一下(这看一下没有限制的,可以看到结尾)。

  • exp1(?=exp2)

寻找后面是 exp2 的 exp1

  • exp1(?!exp2)

后顾

  • (?<=exp1)exp2

匹配 exp1 后面的 exp2,前面没有exp1的内容将被忽略,比如,替换abcba替换c后面的bxxx,需要写为:

"abcba".replaceAll("(?<=c)b", "xxx")

a后面的b则不受影响。

注意:正则表达式(?<=c)b不会匹配字符串cb,意思就是:

assertFalse("cb".matches("(?<=c)b"));
assertFalse("b".matches("(?<=c)b"));
assertTrue("cb".matches("c(?<=c)b"));
  • (?<!exp1)exp2

后顾中带有 < ,并且只影响后面的表达式,也就是说,你如果写成这样:exp2(?<=exp1),是没什么卵用的。

以下内容来自另一篇文章
原文链接:https://blog.csdn.net/handsomexiaominge/article/details/87886857

非获取匹配

当我们使用正则表达式的时候,捕获的字符串会被缓存起来以供后续使用,具体表现为每个()中的表达式所匹配到的内容在进行正则匹配的过程中,都会被缓存下来,如以下代码

var testReg=/(a+)(b*)c/;
testReg.test('aaaabbbccc');//输出true
console.log(RegExp.$1);//输出aaaa
console.log(RegExp.$2);//输出bbb

但是,如果在子分组中加入?:之后,分组依然成立,但是不会被缓存下来,看以下代码

var testReg=/(a+)(?:b*)c/;
testReg.test('aaaabbbccc');//输出true
console.log(RegExp.$1);//输出aaaa
console.log(RegExp.$2);//输出""

断言

我们知道,正则表达式中大部分的结构所匹配的文本最终会出现在匹配结果中,但也有一部分结构并不真正匹配文本,而只是负责判断某个位置左/右侧是否符合要求,这种结构被称为断言

常用的断言有以下四种

(?=pattern)非获取匹配,正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用。
(?!pattern)非获取匹配,正向否定预查,在任何不匹配pattern的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用。
(?<=pattern)非获取匹配,反向肯定预查,与正向肯定预查类似,只是方向相反。
(?<!patte_n)非获取匹配,反向否定预查,与正向否定预查类似,只是方向相反。

牛刀小试

以下所有内容只能使用String#repalceAll或者String#matches完成。

手机号遮罩

11位手机号除前4位之外,其他的使用*替换。

格式化数字

例如:1234567890 使用正则替换之后,变为 1,234,567,890

Trim 字符串

使用正则去除字符串开始和结束的空白字符。

去除数字结尾的0

1234.4500应该处理为1234.451234.00应该处理为1234

处理文档

将字符串的* 测试 * ** 测试 **的使用单个*包围的内容两边分别加上<h1></h1>,不能影响两个**包围的内容。

测试某个字符串是不是合法的Java标识符

测试IPv4

已知IPv4中每一段的数字需要介于0~255,测试某个字符串是否是合法的IPv4表达式。

去除//注释

已知Java中可以使用// 进行单行注释,请去除一段代码中的这种注释。

去除/* 内容 */注释

已知Java中可以使用/* */ 进行多行注释,请去除代码中的这种注释。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值