JavaRush /Java 博客 /Random-ZH /Java 中的正则表达式,第 2 部分

Java 中的正则表达式,第 2 部分

已在 Random-ZH 群组中发布
我们向您展示 Java 正则表达式简短指南的翻译,该指南由 Jeff Friesen 为javaworld网站编写。为了方便阅读,我们将文章分为几个部分。 Java 中的正则表达式,第 2 部分 - 1Java 中的正则表达式,第 1 部分
合并多个范围
您可以通过并排放置多个范围将它们合并到单个范围字符类中。例如,该类[a-zA-Z]匹配所有小写或大写的拉丁字母字符。

合并多个范围

您可以通过并排放置多个范围将它们合并到单个范围字符类中。例如,该类[a-zA-Z]匹配所有小写或大写的拉丁字母字符。

组合字符类

字符类联合由多个嵌套字符类组成,并匹配生成的联合中的所有字符。例如,该类[a-d[m-p]]匹配字符 from atod和 from mto p。考虑以下示例: 此示例将查找、、和,其中 中存在匹配的java RegexDemo [ab[c-e]] abcdef 字符 、、和: abcdeabcdef
regex = [ab[c-e]]
input = abcdef
Found [a] starting at 0 and ending at 0
Found [b] starting at 1 and ending at 1
Found [c] starting at 2 and ending at 2
Found [d] starting at 3 and ending at 3
Found [e] starting at 4 and ending at 4

字符类交集

字符类的交集由所有嵌套类共有的字符组成,并且仅匹配公共字符。例如,该类[a-z&&[d-f]]匹配字符d,ef。请考虑以下示例: java RegexDemo "[aeiouy&&[y]]" party 请注意,在我的 Windows 操作系统上,需要双引号,因为命令 shell 将它们视为&命令分隔符。y此示例将仅查找在 中匹配的字符party
regex = [aeiouy&&[y]]
input = party
Found [y] starting at 4 and ending at 4

减去字符类

减去字符类由除嵌套字符类中包含的字符之外的所有字符组成,并且仅匹配那些剩余的字符。例如,该类[a-z&&[^m-p]]匹配字符 from atol和 from qto z: 此示例将查找在 中匹配的java RegexDemo "[a-f&&[^a-c]&&[^e]]" abcdefg 字符d和: fabcdefg
regex = [a-f&&[^a-c]&&[^e]]
input = abcdefg
Found [d] starting at 3 and ending at 3
Found [f] starting at 5 and ending at 5

预定义字符类

某些字符类在正则表达式中出现的频率足够高,足以证明使用简写符号是合理的。该类Pattern提供预定义的字符类作为此类缩写。您可以使用它们来简化正则表达式并最大限度地减少语法错误。预定义字符类有多种类别:标准、POSIXjava.lang.Character和 Unicode 属性,例如脚本、块、类别和二进制。以下列表仅显示标准类的类别:
  • \d: 数字。相等的[0-9]
  • \D: 非数字字符。相等的[^0-9]
  • \s:空白字符。相等的[ \t\n\x0B\f\r]
  • \S: 不是空白字符。相等的[^\s]
  • \w:构词符号。相等的[a-zA-Z_0-9]
  • \W: 不是构词字符。相等的[^\w]
以下示例使用预定义的字符类\w来描述输入文本中的所有单词字符: java RegexDemo \w "aZ.8 _" 仔细观察以下执行结果,可以看出句点和空格字符不被视为单词字符:
regex = \w
input = aZ.8 _
Found [a] starting at 0 and ending at 0
Found [Z] starting at 1 and ending at 1
Found [8] starting at 3 and ending at 3
Found [_] starting at 5 and ending at 5
行分隔符
类 SDK 文档Pattern将点元字符描述为预定义的字符类,它匹配除行分隔符(标记行结尾的一个或两个字符序列)之外的任何字符。dotall 模式是个例外(我们将在接下来讨论),其中点也与行分隔符匹配。该类区分Pattern以下行分隔符:
  • 回车符 ( \r);
  • 换行符(纸张前进一行的符号)( \n);
  • 回车符后紧跟换行符 ( \r\n);
  • 下一行字符 ( \u0085);
  • 行分隔符 ( \u2028);
  • 段落分隔符 ( \u2029)

捕获的群体

捕获组用于保存找到的字符集,以便在按模式搜索时进一步使用。此构造是用括号 ( ) 括在元字符中的字符序列( )。按模式搜索时,捕获组中的所有字符都被视为一个整体。例如,捕获组 ( Java) 将字母Jav和组合a成一个单元。Java该捕获组查找输入文本中出现的所有模式。每次匹配时,先前存储的字符Java都会被下一个字符替换。捕获的组可以嵌套在其他捕获的组中。例如,在正则表达式中,(Java( language))(language)嵌套在组内(Java)。每个嵌套或非嵌套捕获组都分配有一个编号,从 1 开始,从左到右编号。在前面的示例中,(Java( language))匹配捕获组编号 1 并(language)匹配捕获组编号 2。在正则表达式 中(a)(b)(a)匹配捕获组编号 1 和(b)捕获组编号 2。 Java 中的正则表达式,第 2 部分 - 2稍后可以使用反向引用访问捕获组存储的匹配项。反向引用指定为反斜杠字符后跟与正在捕获的组的编号相对应的数字字符,允许您引用该组捕获的文本中的字符。具有反向链接会导致匹配器根据捕获的组中的数字引用其存储的搜索结果,然后使用该结果中的字符来尝试进一步搜索。以下示例显示如何使用反向引用来查找文本中的语法错误: java RegexDemo "(Java( language)\2)" "The Java language language" 此示例使用正则表达式来查找输入文本中紧随其后的(Java( language)\2)重复单词的语法错误。此正则表达式指定要捕获的两个组:数字 1 –对应于,数字 2 –对应于后跟的空格字符。后向引用允许重新访问组号 2 的存储结果,以便匹配器可以在第一次出现空格和 后搜索第二次出现的空格,后跟。匹配器的结果如下: languageJava"The Java language language"(Java( language)\2)Java language language(language)language\2languagelanguageRegexDemo
regex = (Java( language)\2)
input = The Java language language
Found [Java language language] starting at 4 and ending at 25

边界匹配器

有时您需要在行首、单词边界、文本末尾等处执行模式匹配。您可以使用边缘匹配器类之一来执行此操作Pattern,这些匹配器是正则表达式构造,可在以下位置搜索匹配项:
  • ^:行首;
  • $: 行结束;
  • \b:字边界;
  • \B:伪字边界;
  • \A:文本开始;
  • \G:上一场比赛结束;
  • \Z:文本结束,不包括尾随行分隔符(如果存在);
  • \z: 正文结束
以下示例使用^边界匹配器元字符查找以 开头The,后跟零个或多个单词字符的行: java RegexDemo "^The\w*" Therefore 该字符^指定输入文本的前三个字符必须与连续的模式字符Th和匹配e,后面可以跟任意数字的构词符号。这是执行结果:
regex = ^The\w*
input = Therefore
Found [Therefore] starting at 0 and ending at 8
如果将命令行更改为 会发生什么java RegexDemo "^The\w*" " Therefore"Therefore由于输入文本前面有空格字符,因此 找不到匹配项。

零长度匹配

有时,在使用边缘匹配器时,您会遇到零长度匹配。Совпадение нулевой длины是不包含任何字符的匹配。它们可以出现在空输入文本中、输入文本的开头、输入文本的最后一个字符之后以及输入文本的任意两个字符之间。零长度匹配很容易识别,因为它们总是在同一位置开始和结束。考虑以下示例: java RegExDemo \b\b "Java is" 此示例搜索两个连续的单词边界,结果如下所示:
regex = \b\b
input = Java is
Found [] starting at 0 and ending at -1
Found [] starting at 4 and ending at 3
Found [] starting at 5 and ending at 4
Found [] starting at 7 and ending at 6
我们在结果中看到几个零长度匹配。这里的结束位置比起始位置少 1,因为RegexDemo我在 清单 1 的源代码中指定了end() – 1Java 中的正则表达式,第 2 - 3 部分

量词

量词是一种正则表达式构造,它显式或隐式地将模式与数值关联起来。该数值决定搜索模式的次数。量词分为贪婪量词、懒惰量词和超贪婪量词:
  • 贪婪量词(?*+)旨在查找最长匹配。请问X?查找一次或更少的出现次数XX*查找零次或多次出现次数XX+查找一次或多次出现次数XX{n}查找次数、查找至少(并且可能更多)次出现次数以及查找至少但不多次出现次数。nXX{n,}nXX{n,m}nmX
  • 惰性量词(??,*?+?)旨在查找最短匹配。您可以指定X??搜索 1 次或更少出现的X, X*? 查找零个或多个出现的情况XX+?查找一个或多个出现的情况XX{n}?查找n出现的情况XX{n,}?查找至少(可能有更多)n出现的情况X以及X{n,m}?查找至少n但不超过m出现的情况X
  • 超贪婪量词(?+*+++)与贪婪量词类似,不同之处在于超贪婪量词仅尝试一次来查找最长匹配,而贪婪量词可以进行多次尝试。可以设置X?+为查找 1 次或更少的出现次数XX*+查找0 次或多次出现次数XX++查找 1 次或多次出现次数X、查找 的出现次数、查找至少(也可能更多)次出现次数以及查找至少但不超过1 个出现次数。X{n}+nXX{n,}+nXX{n,m}+ nmX
以下示例说明了贪婪量词的使用: java RegexDemo .*ox "fox box pox" 以下是结果:
regex = .*ox
input = fox box pox
Found [fox box pox] starting at 0 and ending at 10
贪婪量词 ( .*) 查找以 结尾的最长字符序列ox。它会消耗整个输入文本,然后回滚,直到检测到输入文本以这些字符结尾。现在考虑惰性量词: java RegexDemo .*?ox "fox box pox" 它的结果:
regex = .*?ox
input = fox box pox
Found [fox] starting at 0 and ending at 2
Found [ box] starting at 3 and ending at 6
Found [ pox] starting at 7 and ending at 10
惰性量词 ( .*?) 查找以 结尾的最短字符序列ox。它以空白字符串开始,逐渐消耗字符,直到找到匹配项。然后继续工作,直到输入文本用完。最后,让我们看看超贪婪量词: java RegexDemo .*+ox "fox box pox" 这是它的结果:
regex = .*+ox
input = fox box pox
超贪婪量词 ( .*+) 找不到匹配项,因为它消耗了所有输入文本,并且正则ox表达式末尾没有任何内容可匹配。与贪婪量词不同,超贪婪量词不会回滚。

零长度匹配

有时,在使用量词时,您会遇到零长度匹配。例如,使用以下贪婪量词会导致多个零长度匹配: java RegexDemo a? abaa 运行此示例的结果:
regex = a?
input = abaa
Found [a] starting at 0 and ending at 0
Found [] starting at 1 and ending at 0
Found [a] starting at 2 and ending at 2
Found [a] starting at 3 and ending at 3
Found [] starting at 4 and ending at 3
执行结果中有5个匹配项。a虽然第一、第三和第四个是相当意料之中的(它们对应于中三个字母的位置abaa),但第二个和第五个可能会让你感到惊讶。看起来好像它们表明了与文本结尾a相对应的b内容,但实际上情况并非如此。正则表达式a?不会b在文本末尾进行搜索。它搜索存在或不存在a。当a?它没有找到时a,它会将其报告为零长度匹配。

嵌套标志表达式

匹配器会做出一些默认假设,在将正则表达式编译为模式时可以覆盖这些默认假设。我们稍后再讨论这个问题。正则表达式允许您使用嵌套标志表达式覆盖任何默认值。此正则表达式构造被指定为问号元字符 ( ) 周围的括号元字符?,后跟一个小写拉丁字母。该类Pattern理解以下嵌套标志表达式:
  • (?i):启用不区分大小写的模式匹配。例如,使用命令时,java RegexDemo (?i)tree Treehouse字符序列Tree与模式匹配tree。默认是区分大小写的模式搜索。
  • (?x):允许在模式中使用以元字符开头的空白字符和注释#。匹配器将忽略两者。例如,对于匹配模式java RegexDemo ".at(?x)#match hat, cat, and so on" matter的字符序列。默认情况下,不允许使用空格字符和注释,匹配器将它们视为搜索中涉及的字符。mat.at
  • (?s):启用 dotall 模式,在该模式下,点元字符除了匹配任何其他字符外,还匹配行分隔符。例如,该命令java RegexDemo (?s). \n将查找换行符。默认值与 dotall 相反:不会找到行分隔符。例如,该命令Java RegexDemo . \n将找不到换行符。
  • (?m):启用多行模式,匹配每行的^开头和$结尾。例如,java RegexDemo "(?m)^abc$" abc\nabc在输入文本中查找两个序列abc。默认情况下,使用单行模式:^匹配整个输入文本的开头,并$匹配其结尾。例如,java RegexDemo "^abc$" abc\nabc返回没有匹配项的响应。
  • (?u):启用 Unicode 敏感的大小写对齐。该标志与 结合使用时(?i),允许根据 Unicode 标准进行不区分大小写的模式匹配。默认设置是仅搜索区分大小写和 US-ASCII 字符。
  • (?d):启用 Unix 风格的字符串模式,其中匹配器识别上下文中的元字符.^并且$仅识别行分隔符\n。默认是非 Unix 风格的字符串模式:匹配器在上述元字符的上下文中识别所有行分隔符。
嵌套标志表达式类似于捕获组,因为它们的字符被括号元字符包围。与捕获组不同,嵌套标志表达式是非捕获组的一个示例,非捕获组是不捕获文本字符的正则表达式构造。它们被定义为由括号元字符包围的字符序列。
指定多个嵌套标志表达式
可以在正则表达式中指定多个嵌套标志表达式,方法是将它们并排放置 ( (?m)(?i))),或按顺序放置定义它们的字母 ( (?mi))。

结论

您现在可能已经意识到,正则表达式非常有用,并且当您掌握其语法的细微差别时,它会变得更加有用。到目前为止,我已经向您介绍了正则表达式和Pattern. Pattern在第 2 部分中,我们将深入研究 Regex API 并探索,Matcher和的方法PatternSyntaxException。我还将向您展示 Regex API 的两个实际应用程序,您可以立即在程序中使用它们。 Java 中的正则表达式,第 3 部分 Java 中的正则表达式,第 4 部分 Java 中的正则表达式,第 5 部分
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION