【Java正则表达式系列】6. Quantifiers(量词)

在前面的几个章节中,我们简单的学习了一些基本的正则表达式的一些元素,今天,我们来讨论一下Java 正则表达式重要的一个概念–Quantifiers(量词).

啥为量词?从字面意义上可能和数量有关,其实Java 正则里面的量词被用来需要指定某种模式需要重复出现一定次数的情况,比如:我们想匹配100个连续的a, 当然了,你可以写100个a的正则表达式来达到同样的功能,但是,这种也太辛苦了,我们程序员是很懒的。所以学习Quantifier相关知识,可以少搬一点砖<_

1.Quantifier的分类

在Java的Pattern类的java doc中其描述了三种类型的,下面列举三种的内容:

GreedyReluctantPossessiveMeaning翻译
X?X??X?+X, once or not at allX字符出现一次或者没有匹配
X*X*?X*+X, zero or more timesX字符出现0次或者多次
X+X+?X++X, one or more timesX字符至少重复出现1次
X{n}X{n}?X{n}+X, exactly n timesX字符重复n次
X{n,}X{n,}?X{n,}+X, at least n timesX字符至少重复n次
X{n,m}X{n,m}?X{n,m}+X, at least n but not more than m timesX字符至少出现n次,但不会超过m次

上面几种类型对应的中文描述是: Greedy–贪婪型(最大匹配) Reluctant–勉强型(最小匹配), Possessive—占有型(全部匹配),在后续内容我将继续使用英文。

咋眼一看,X?, X??X?+做着同样的事情,它们都是用来匹配字符X出现一次或者没有出现, 其实这个问题开始学习确实烦的要死,后面的部分说明它们之间的细微差别。

这里让大家了解一下*,?+这几个Metacharater的意思,下面几个实验中,带匹配的空字符串,即”“.

这里写图片描述

这里写图片描述

这里写图片描述

通过上面的几个例子,我们简单列举它们具体的意义:
1. *:字符出现的次数>=0;
2. ?: 字符出现的次数要么是1,要么是0次;
3. +:字符出现的次数>=1;

2. Zero-Length Matches(零长度匹配)

这个概念有点奇怪,长度为0的匹配是什么鬼?请大家之前说的匹配start index和 end index.可以通过下面的图了解一下:

这里写图片描述

上面是某次匹配的结果,匹配的子串是原字符串索引1到3为止,不包括3,所以这里面的end index指的是下一次继续寻找匹配子串的起始索引。

那这个和我们现在要说的零长度匹配有什么关系吗? 认真一点的可能会看到上面的头两个示例中,出现了start index = 0 和end index也为0的情况,这个怎么解释呢?

首先我们要了解一下a?a*这两个表达式都允许字符a出现0次的情况,考虑到我们输入的是空字符串,字符串的长度为0, 这时候他们去匹配0长度的时候,没有出现字符a,说明也满足上面两个正则表达式的条件,这种类型的匹配我们称之为“零长度匹配”,它们特征也很明显,就是start index和 end index相等。

这里大概可能有疑问了,空字符串不是长度为0吗?你这里匹配index=0,按道理应该说明字符串是长度为一的字符串啊!!!

是时候表演真正的技术了,这里注意一下end index的意义,上面我有提到它表示下一次匹配的开始,这个时候匹配过程就是去尝试匹配 end index,这时候我们start index就应该调整到end index, 但是匹配的结果让人很心酸—start index没有数据,这时候匹配引擎回溯,当然这时候回溯后的位置还是start index,此时,构造出的是空白,然而这种空白符合a?a*的意,这就是为啥end index = start index, 此时匹配过程结束,原因在于start index已经>= 字符串的长度了,说明已经没有的匹配了。

下面我们在通过几个示例来感受这波骚操作:

这里写图片描述

这里写图片描述

这里写图片描述

下面我将输入字符串长度变大,大家可以看到各个元字符的差异性了:

这里写图片描述

这里写图片描述

这里写图片描述

下面我们再尝试一些非纯a字符的情况:

这里写图片描述

解释: abcaad,
第一次匹配a, 成功,此时打印Found [a] starting at 0 and ending at 1;

第二次匹配b, 失败,但是匹配引擎回溯,此时start index = end index,这样就构成了空串,正则a?匹配这种情况,所以打印: Found [a] starting at 1 and ending at 1;

第三次匹配c,此时start index为2, 为啥是2不是1呢?原因在于 index = 1的位置我们已经匹配过,不要因为匹配引擎回溯,而以为start index = 1, 这里start index应该表示上次已经匹配过的字符索引位置的下一位,即没有匹配过的位,现在匹配d字符,同匹配b一样,打印:*Found [a] starting at 2 and ending at 2;

第四次匹配字符a, 匹配成功,则输出: *Found [a] starting at 3 and ending at 4;

第五次匹配字符a, 匹配成功,则输出: *Found [a] starting at 4 and ending at 5;

第六次匹配字符d,匹配失败,则输出: Found [a] starting at 5 and ending at 5

第七次匹配字符d,匹配失败,则输出: Found [a] starting at 6 and ending at 6

下面再给出两个例子:

这里写图片描述

这里写图片描述

3. 定长匹配

某些情况下,我们希望字符重复出现的次数可控,这是我们可以用大括号表达自己期望的次数,{min, max}.
这个存在三种变形:

FormatMeaning
{num}重复num次
{min,}至少重复num次
{min, max}重复次数在min<= 重复次数 <= max

下面给出几个示例:

这里写图片描述

这里写图片描述

这里写图片描述

上面的学习中,我们仅仅将量词放在单个字符情况,下面我们来讨论量词用在Capturing Groups 和 Character classes的情况.

4. 量词和Capturing Groups和Character Classes的使用

量词用在Capturing Groups和Character Classes时,我们将它们当做一个整体来看待,下面通过例子来了解:

这里写图片描述

这里写图片描述

上面的例子在匹配(dog){3}时,将括号里面的dog看做一个整体来,即dog字符串得重复出现三次,也就是dogdogdog,

然而dog{3}我们这里的{3}修饰的g字符,它匹配的字符是doggg这种情况.

这里写图片描述

下面我们来了解一下Character Classes的情况:

这里写图片描述

对于[abc]{3}表示重复出现的三个字符,可以是字符a, bc中任意一个,所以匹配到可能的子串为: Character Classes Length * repeat Num

5. Greedy、Reluctant和Possessive的区别

Greedy: 从字面意义来看它是贪婪,想一口气吃一个大胖子,它在匹配的时候,总是先整个字符串匹配,匹配不了,它在回退,先看个例子:
这里写图片描述

上面的例子中.*foo先将整个字符串进行匹配,结果发现模式匹配,就返回整个字符串作为结果.

这里写图片描述

reluctant: 表示最小匹配,它总是小口小口的吃,可以通过例子比较一下区别:
这里写图片描述

这里写图片描述

Possessive:表示最大匹配,而且它就匹配一下,匹配不成功,匹配引擎不会回溯的,可以通过如下例子了解:

这里写图片描述

这个为啥不匹配呢?原因在于对于.*+foo而言,.*+匹配完了整个字符,当它继续匹配foo的时候发现找不到了。因为此时没有可供匹配的字符的,故返回”Not Found”。

大概可能就要问了这个Possessive有什么使用场景呢?这个通常用在严格模式上面的匹配,比如邮箱匹配之类的场景。

完!

上一节: 【Java正则表达式系列】5. 预定义Character classes
下一节: 【Java正则表达式系列】7 Capturing Groups(匹配组)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要使用 Java 正则表达式来匹配和获取文本文件,可以按照以下步骤进行: 1. 读取文本文件的内容,可以使用 Java 的文件输入流(FileInputStream)和缓冲输入流(BufferedInputStream)来实现。 2. 使用 Java正则表达式类(Pattern)和匹配器类(Matcher)来编译和匹配正则表达式。例如,可以使用 Pattern 类的 compile() 方法来编译正则表达式,然后使用 Matcher 类的 matcher() 方法来匹配文本文件中的内容。 3. 在正则表达式中使用元字符和特殊字符来匹配文本文件中的内容。例如,可以使用字符类(Character Class)来匹配任何单个字符,或者使用量词Quantifiers)来匹配多个字符。 4. 在匹配成功后,可以使用 Matcher 类的 group() 方法来获取匹配到的内容。 以下是一个示例代码,演示了如何使用 Java 正则表达式来匹配并获取文本文件中的内容: ```java import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.regex.Matcher; import java.util.regex.Pattern; public class FileRegexMatcher { public static void main(String[] args) { String fileName = &quot;file.txt&quot;; String regex = &quot;.*Java.*&quot;; // 匹配包含 Java 的行 try { FileInputStream fis = new FileInputStream(fileName); BufferedReader reader = new BufferedReader(new InputStreamReader(fis)); Pattern pattern = Pattern.compile(regex); String line; while ((line = reader.readLine()) != null) { Matcher matcher = pattern.matcher(line); if (matcher.matches()) { System.out.println(line); } } reader.close(); fis.close(); } catch (IOException e) { e.printStackTrace(); } } } ``` 在这个示例中,我们首先指定了要匹配的文件名和正则表达式。然后,我们使用 FileInputStream 和 BufferedReader 读取文件内容。接着,我们使用 Pattern 类编译正则表达式,并在 while 循环中使用 Matcher 类匹配每一行。最后,如果匹配成功,我们就使用 System.out.println() 输出匹配到的行。 ### 回答2: 在Java中,可以使用正则表达式来进行文件匹配和获取。 首先,我们需要利用Java的File类来访问文件系统,并使用正则表达式来匹配文件名或路径。可以使用File类的listFiles方法来获取指定路径下的所有文件和文件夹。然后,我们可以使用正则表达式来筛选出符合条件的文件。 以下是一个简单的示例代码,假设我们要获取指定目录下以&quot;.txt&quot;为后缀的所有文件: ```java import java.io.File; import java.util.regex.Matcher; import java.util.regex.Pattern; public class FileMatcher { public static void main(String[] args) { String directory = &quot;/path/to/directory&quot;; // 指定目录路径 String regex = &quot;.*\\.txt$&quot;; // 正则表达式,匹配以&quot;.txt&quot;为后缀的文件 File folder = new File(directory); File[] files = folder.listFiles(); // 获取目录下所有文件和文件夹 Pattern pattern = Pattern.compile(regex); // 编译正则表达式 for (File file : files) { if (file.isFile()) { // 判断是否为文件 String filename = file.getName(); // 获取文件名 // 使用正则表达式匹配文件名 Matcher matcher = pattern.matcher(filename); if (matcher.matches()) { // 匹配成功 System.out.println(filename); } } } } } ``` 上述代码中,我们首先指定了一个目录路径和一个正则表达式。然后,通过File类的listFiles方法获取目录下的所有文件和文件夹,并使用正则表达式匹配文件名。对于每个文件,我们使用Matcher类进行匹配,如果匹配成功,则将文件名输出。 通过以上方式,我们可以根据正则表达式来匹配和获取文件。此外,还可以根据需要进行进一步修改和扩展。 ### 回答3: Java中可以使用正则表达式来匹配和获取文件。正则表达式是一种用来描述字符串模式的工具,在Java中可以通过Pattern和Matcher类来实现正则表达式匹配。 首先,我们需要使用正则表达式定义要匹配的文件名模式。例如,如果我们想获取以&quot;.txt&quot;结尾的文件名,我们可以使用正则表达式&quot;^.+\\.txt$&quot;,其中&quot;^&quot;表示匹配字符串的开始,&quot;.+&quot;表示匹配一个或多个任意字符,&quot;\\.&quot;表示匹配点字符,&quot;txt$&quot;表示匹配以&quot;txt&quot;结尾的字符串。 接下来,我们可以使用Pattern.compile方法将正则表达式编译为Pattern对象,并使用Matcher类的find方法进行匹配。例如: ```java String pattern = &quot;^.+\\.txt$&quot;; Pattern regex = Pattern.compile(pattern); File directory = new File(&quot;path/to/directory&quot;); File[] files = directory.listFiles(); for (File file : files) { String fileName = file.getName(); Matcher matcher = regex.matcher(fileName); if (matcher.find()) { System.out.println(&quot;匹配到文件:&quot; + fileName); } } ``` 上述代码首先定义了一个正则表达式模式,并将其编译为Pattern对象。然后,我们通过File类的listFiles方法获取指定目录下的文件列表。接下来,遍历文件列表,对每个文件名使用Matcher类的find方法进行匹配,如果匹配成功则输出匹配到的文件名。 注意,在使用正则表达式进行文件匹配时,还可以使用其他的符号和模式来定义匹配规则,具体的语法和技巧可以参考正则表达式相关的文档和教程。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值