Java程序设计(高级及专题)- 正则表达式(1)

while (matcher.find()) {

String res = matcher.group();

System.out.println(index + “:” + res);

index++;

}

\\ba\\w*\\b表示匹配以字母a为开头的单词。

Pattern.compile(regex)表示将给定的正则表达式编译到具有给定标志的模式中。

matcher(str)创建匹配给定输入与此模式的匹配器。

mather.find()尝试查找与该模式匹配的输入序列的下一个子序列。

此方法从匹配器区域的开头开始,如果该方法的前一次调用成功了并且从那时开始匹配器没有被重置,则从以前匹配操作没有匹配的第一个字符开始。

如果匹配成功,则可以通过 start、end 和 group 方法获取更多信息。

group() 返回由以前匹配操作所匹配的输入子序列。

打印结果:

不同

从上例中可以看出,Java中的正则表达式与之前所说不一致(多了一个),在其他语言中\\表示我想在正则表达式中插入一个普通的反斜线,请不要给它任何特殊的意义,而在Java中,\\的意思是我想要插入一个正则表达式的反斜线,所以其后的字符具有特殊的意义。

如果想表示数字,则是\\d。如果要插入普通的反斜线,则是\\\\

String

String类中有几种方法可以使用正则表达式:

| 方法 | 返回类型 | 功能 | 示例 |

| — | — | — | — |

| matches() | boolean | 告知此字符串是否匹配给定的正则表达式。 | "-1234".matches("^-?\\d+$") => true |

| replaceAll(String regex, String replacement) | String | 使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。 | "a1b2c3".replaceAll("[a-zA-z]", "") => 123 |

| replaceFirst(String regex, String replacement) | String | 使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。 | "Hello World! Hello Everyone!".replaceFirst("\\s", "") => HelloWorld! Hello Everyone! |

| split(String regex) | String[] | 根据给定正则表达式的匹配拆分此字符串。 | "boo:and:foo".split(":") => { "boo", "and", "foo" } |

| split(String regex, int limit) | String[] | 根据给定正则表达式的匹配拆分此字符串。 | "boo:and:foo".split(":", 5) => { "boo", "and", "foo" } |

split(String regex, int limit)方法中limit 参数控制模式应用的次数,因此影响所得数组的长度。如果该限制 n 大于 0,则模式将被最多应用 n - 1 次,数组的长度将不会大于 n,而且数组的最后一项将包含所有超出最后匹配的定界符的输入。如果 n 为非正,那么模式将被应用尽可能多的次数,而且数组可以是任何长度。如果 n 为 0,那么模式将被应用尽可能多的次数,数组可以是任何长度,并且结尾空字符串将被丢弃。

例如,字符串 "boo:and:foo" 使用这些参数可生成以下结果:

| Regex | Limit | 结果 |

| — | — | — |

| : | 2 | { "boo", "and:foo" } |

| : | 5 | { "boo", "and", "foo" } |

| : | -2 | { "boo", "and", "foo" } |

| o | 5 | { "b", "", ":and:f", "", "" } |

| o | -2 | { "b", "", ":and:f", "", "" } |

| o | 0 | { "b", "", ":and:f" } |

调用此方法的 str.split(regex, n) 形式与以下表达式产生的结果完全相同:Pattern.compile(regex).split(str, n)

java.util.regex

在regex包中,包括了两个类,Pattern(模式类)和Matcher(匹配器类)。Pattern类是用来表达和陈述所要搜索模式的对象,Matcher类是真正影响搜索的对象。另加一个新的例外类,PatternSyntaxException,当遇到不合法的搜索模式时,会抛出例外。

Pattern

  • 简介

正则表达式的编译表示形式。

指定为字符串的正则表达式必须首先被编译为此类的实例。然后,可将得到的模式用于创建 Matcher 对象,依照正则表达式,该对象可以与任意字符序列匹配。执行匹配所涉及的所有状态都驻留在匹配器中,所以多个匹配器可以共享同一模式。

因此,典型的调用顺序是

Pattern p = Pattern.compile(“a*b”);

Matcher m = p.matcher(“aaaaab”);

boolean b = m.matches();

在仅使用一次正则表达式时,可以方便地通过此类定义 matches 方法。此方法编译表达式并在单个调用中将输入序列与其匹配。语句

boolean b = Pattern.matches("a*b", "aaaaab");

等效于上面的三个语句,尽管对于重复的匹配而言它效率不高,因为它不允许重用已编译的模式。

此类的实例是不可变的,可供多个并发线程安全使用。Matcher 类的实例用于此目的则不安全。

  • 常用方法

  • Pattern类中最重要的方法便是compilematcher,上面已经给出示例。下面看看其他方法:

| 方法 | 返回类型 | 功能 | 示例 |

| — | — | — | — |

| flags() | int | 返回此模式的匹配标志。 | Pattern.compile("\\w*", Pattern.MULTILINE).flags() => 8 |

| pattern() | String | 返回在其中编译过此模式的正则表达式。 | Pattern.compile("\\w*").pattern() => \w* |

| static quote(String s) | String | 返回指定 String 的字面值模式 String。 | Pattern.quote("\\w+") => \Q\w+\E |

Matcher

  • 简介

通过解释 Pattern 对 character sequence 执行匹配操作的引擎。

通过调用模式的 matcher 方法从模式创建匹配器。创建匹配器后,可以使用它执行三种不同的匹配操作:

  • matches 方法尝试将整个输入序列与该模式匹配。

  • lookingAt 尝试将输入序列从头开始与该模式匹配。

  • find 方法扫描输入序列以查找与该模式匹配的下一个子序列。

每个方法都返回一个表示成功或失败的布尔值。通过查询匹配器的状态可以获取关于成功匹配的更多信息。

匹配器在其输入的子集(称为区域)中查找匹配项。默认情况下,此区域包含全部的匹配器输入。可通过 region 方法修改区域,通过 regionStart 和 regionEnd 方法查询区域。区域边界与某些模式构造交互的方式是可以更改的。

此类还定义使用新字符串替换匹配子序列的方法,需要时,可以从匹配结果计算出新字符串的内容。可以先后使用 appendReplacement 和 appendTail 方法将结果收集到现有的字符串缓冲区,或者使用更加便捷的 replaceAll 方法创建一个可以在其中替换输入序列中每个匹配子序列的字符串。

匹配器的显式状态包括最近成功匹配的开始和结束索引。它还包括模式中每个捕获组捕获的输入子序列的开始和结束索引以及该子序列的总数。出于方便的考虑,还提供了以字符串的形式返回这些已捕获子序列的方法。

匹配器的显式状态最初是未定义的;在成功匹配导致 IllegalStateException 抛出之前尝试查询其中的任何部分。每个匹配操作都将重新计算匹配器的显式状态。

匹配器的隐式状态包括输入字符序列和添加位置,添加位置最初是零,然后由 appendReplacement 方法更新。

可以通过调用匹配器的 reset() 方法来显式重置匹配器,如果需要新输入序列,则调用其 reset(CharSequence) 方法。重置匹配器将放弃其显式状态信息并将添加位置设置为零。

此类的实例用于多个并发线程是不安全的。

  • 常用方法

matches()

表示字符串完全符合给出的正则表达式所表示的范围。只要有一个字符不匹配则返回false。如:

Pattern.matches("[a-z]", "aAbBcC")

返回false,因为正则表达式表示的范围不包含大写字母。

find()

find()尝试查找与该模式匹配的输入序列的下一个子序列。

此方法从匹配器区域的开头开始,如果该方法的前一次调用成功了并且从那时开始匹配器没有被重置,则从以前匹配操作没有匹配的第一个字符开始。

如果匹配成功,则可以通过 start、end 和 group 方法获取更多信息。

Pattern pattern = Pattern.compile(“[a-z]”);

Matcher matcher = pattern.matcher(“aAbBcC”);

matcher.find();

返回true,因为可以匹配到小写字母。

需要注意的是在执行find()方法时,其内部指针会跟着变动,比如第一次调用完毕,此时的matcher.start()为0,因为第一个字母就匹配上了,而matcher.end()则返回2,因为它返回的是最后不匹配(A)的位置的下一个索引,因此可以通过如下方法看到指针移动轨迹:

Pattern p = Pattern.compile(“\d{3,5}”);

String s = “123-34345-234-00”;

while (m.find()) {

System.out.println(m.start() + “-” + m.end());

}

打印结果:

可以看到,find方法比较实诚,善始善终,但我们有时候需要人工插手而不总是从头到尾来一遍,这就涉及到find方法的另一个多态形式了。

find(int start)

从指定位置开始匹配,使用此方法模拟find():

int index = 0;

while (m.find(index)) {

System.out.println(m.start() + “-” + m.end());

index = m.end();

}

lookingAt()

此方法总是从头开始匹配,无论是否匹配上均立即返回相应结果,并且不再继续匹配,语言乏力,此处使用find方法模拟:

public static void main(String[] args) throws Exception {

Pattern p = Pattern.compile(“\d{3,5}”);

String s = “123-34345-234-00”;

Matcher m = p.matcher(s);

System.out.println(cosplayMethodLookingAt(m));

System.out.println(cosplayMethodLookingAt(m));

System.out.println(cosplayMethodLookingAt(m));

System.out.println(cosplayMethodLookingAt(m));

}

private static boolean cosplayMethodLookingAt(Matcher m) {

boolean res = m.find() && m.start() == 0;

m.reset();

return res;

}

显示效果与lookingAt方法相同,但内部实现不一样:

public static void main(String[] args) throws Exception {

Pattern p = Pattern.compile(“\d{3,5}”);

String s = “123-34345-234-00”;

Matcher m = p.matcher(s);

m.find();

m.lookingAt();

m.find();

// 4

System.out.println(m.start());

cosplayMethodLookingAt(m);

m.find();

System.out.println(m.start());

}

private static boolean cosplayMethodLookingAt(Matcher m) {

boolean res = m.find() && m.start() == 0;

m.reset();

return res;

}

打印结果:

由此可见,lookingAt方法并不会重置匹配使用的内部指针。

appendReplacement

public Matcher appendReplacement(StringBuffer sb, String replacement)

实现非终端添加和替换步骤。

此方法执行以下操作:

它从添加位置开始在输入序列读取字符,并将其添加到给定字符串缓冲区。在读取以前匹配之前的最后字符(即位于索引 start() - 1 处的字符)之后,它就会停止。

它将给定替换字符串添加到字符串缓冲区。

它将此匹配器的添加位置设置为最后匹配位置的索引加 1,即 end()。

替换字符串可能包含到以前匹配期间所捕获的子序列的引用:g每次出现时,都将被group(g)的计算结果替换。g每次出现时,都将被group(g)的计算结果替换。 之后的第一个数始终被视为组引用的一部分。如果后续的数可以形成合法组引用,则将被合并到 g 中。只有数字 ‘0’ 到 ‘9’ 被视为组引用的可能组件。例如,如果第二个组匹配字符串 “foo”,则传递替换字符串 "2bar"将导致"foobar"被添加到字符串缓冲区。可能将美元符号(2bar"将导致"foobar"被添加到字符串缓冲区。可能将美元符号() 作为替换字符串中的字面值(通过前面使用一个反斜线 ($))包括进来。

注意,在替换字符串中使用反斜线 () 和美元符号 ($) 可能导致与作为字面值替换字符串时所产生的结果不同。美元符号可视为到如上所述已捕获子序列的引用,反斜线可用于转义替换字符串中的字面值字符。

此方法设计用于循环以及 appendTail 和 find 方法中。例如,以下代码将 one dog two dogs in the yard 写入标准输出流中:

Pattern p = Pattern.compile(“cat”);

Matcher m = p.matcher(“one cat two cats in the yard”);

StringBuffer sb = new StringBuffer();

while (m.find()) {

m.appendReplacement(sb, “dog”);

}

m.appendTail(sb);

System.out.println(sb.toString());

输出结果:

appendTail

StringBuffer appendTail(StringBuffer sb)

此方法从添加位置开始从输入序列读取字符,并将其添加到给定字符串缓冲区。可以在一次或多次调用 appendReplacement 方法后调用它来复制剩余的输入序列。

以上例来说,当匹配到第二个cat时,while语句块中的代码就失效了,此时后面的字符串s in the yard就需要使用appendTail方法来补齐,否则输出结果就是:显然有所缺失。

group

String group()

返回由以前匹配操作所匹配的输入子序列。

对于具有输入序列 s 的匹配器 m,表达式 m.group() 和 s.substring(m.start(), m.end()) 是等效的。

注意,某些模式(例如,a*)匹配空字符串。当模式成功匹配输入中的空字符串时,此方法将返回空字符串。

group(int group)

String group(int group)

返回在以前匹配操作期间由给定组捕获的输入子序列。

对于匹配器 m、输入序列 s 和组索引 g,表达式 m.group(g) 和 s.substring(m.start(g), m.end(g)) 是等效的。

捕获组是从 1 开始从左到右的索引。组零表示整个模式,因此表达式 m.group(0) 等效于 m.group()。

如果该匹配成功了,但指定组未能匹配输入序列的任何部分,则返回 null。注意,某些组(例如,(a*))匹配空字符串。当这些的组成功匹配输入中的空字符串时,此方法将返回空字符串。

Pattern p = Pattern.compile(“\b\w+(o\w+)\b”);

Matcher m = p.matcher(“i love you”);

while (m.find()) {

System.out.println(“整个匹配结果=>”+m.group());

System.out.println(“一组匹配结果=>”+m.group(1));

}

输出结果:

其他

其他方法要么可以融会贯通,比如start(int),要么就是不常用,比如hasAnchoringBounds(),因此在需要的时候可以查看中文文档。

奉上连接:Matcher

常用正则


校验数字的表达式

数字:^[0-9]*$

n位的数字:^\d{n}$

至少n位的数字:^\d{n,}$

m-n位的数字:^\d{m,n}$

零和非零开头的数字:^(0|[1-9][0-9]*)$

非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$

带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})?$

正数、负数、和小数:^(\-|\+)?\d+(\.\d+)?$

有两位小数的正实数:^[0-9]+(.[0-9]{2})?$

有1~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$

非零的正整数:^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$

非零的负整数:^\-[1-9][]0-9″*$ 或 ^-[1-9]\d*$

非负整数:^\d+$ 或 ^[1-9]\d*|0$

非正整数:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$

非负浮点数:^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$

非正浮点数:^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$

正浮点数:^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$

负浮点数:^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$

浮点数:^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$

校验字符的表达式

汉字:^[\u4e00-\u9fa5]{0,}$

英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$

长度为3-20的所有字符:^.{3,20}$

由26个英文字母组成的字符串:^[A-Za-z]+$

分享

1、算法大厂——字节跳动面试题

2、2000页互联网Java面试题大全

3、高阶必备,算法学习

d*|0.\d*[1-9]\d* ‘  或  ‘ ( ( [ 0 − 9 ] + [ ˙ 0 − 9 ] ∗ [ 1 − 9 ] [ 0 − 9 ] ∗ ) ∣ ( [ 0 − 9 ] ∗ [ 1 − 9 ] [ 0 − 9 ] ∗ [ ˙ 0 − 9 ] + ) ∣ ( [ 0 − 9 ] ∗ [ 1 − 9 ] [ 0 − 9 ] ∗ ) ) ` 或 `^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)) ‘  (([09]+[˙09][19][09])([09][19][09][˙09]+)([09][19][09]))`

负浮点数:^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$

浮点数:^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$

校验字符的表达式

汉字:^[\u4e00-\u9fa5]{0,}$

英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$

长度为3-20的所有字符:^.{3,20}$

由26个英文字母组成的字符串:^[A-Za-z]+$

分享

1、算法大厂——字节跳动面试题

[外链图片转存中…(img-w6zbAEbw-1714384570494)]

2、2000页互联网Java面试题大全

[外链图片转存中…(img-Y2POlu5u-1714384570494)]

3、高阶必备,算法学习

[外链图片转存中…(img-oZq00IyO-1714384570494)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 20
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值