RegEx 正则表达式是什么?
事实上,正则表达式(Java 中的 RegEx)是一种在文本中搜索字符串的模式。在Java中,这种模式的初始表示总是一个字符串,即String类的对象。但是,并不是任何字符串都可以编译为正则表达式,只有那些遵循正则表达式编写规则(语言规范中定义的语法)的字符串才可以编译为正则表达式。要编写正则表达式,需要使用字母和数字字符以及元字符 - 在正则表达式语法中具有特殊含义的字符。例如:String regex = "java"; // string template "java";
String regex = "\\d{3}"; // string template of three numeric characters;
在 Java 中创建正则表达式
要在 Java 中创建 RegEx,您需要遵循两个简单的步骤:- 使用正则表达式语法将其写为字符串;
- 将此字符串编译为正则表达式;
Pattern
。为此,您需要调用类中可用的两个静态方法之一compile
。第一个方法采用一个参数 - 正则表达式的字符串文字,第二个 - 加上另一个参数,用于打开将模板与文本进行比较的模式:
public static Pattern compile (String literal)
public static Pattern compile (String literal, int flags)
可能的参数值列表flags
是在类中定义的Pattern
,并且可以作为静态类变量提供给我们。例如:
Pattern pattern = Pattern.compile("java", Pattern.CASE_INSENSITIVE);//searching for matches with the pattern will be done case-insensitively.
本质上,该类Pattern
是一个正则表达式构造函数。在底层,该方法compile
调用类的私有构造函数Pattern
来创建编译视图。实现这种创建模板实例的方法的目的是将其创建为不可变对象。创建时,会执行正则表达式的语法检查。如果该行中有错误,则会生成异常PatternSyntaxException
。
正则表达式语法
正则表达式语法基于符号的使用<([{\^-=$!|]})?*+.>
,符号可以与字母字符组合。根据他们的角色,他们可以分为几组:
元字符 | 目的 |
---|---|
^ | 行首 |
$ | 行结束 |
\b | 字边界 |
\B | 没有字数限制 |
\A | 输入开始 |
\G | 上一场比赛结束 |
\Z | 输入结束 |
\z | 输入结束 |
元字符 | 目的 |
---|---|
\d | 数字符号 |
\D | 非数字字符 |
\s | 空格字符 |
\S | 非空白字符 |
\w | 字母数字字符或下划线 |
\W | 除字母、数字或下划线之外的任何字符 |
。 | 任何字符 |
元字符 | 目的 |
---|---|
\t | 制表符 |
\n | 换行符 |
\r | 回车符 |
\F | 转到新页面 |
\u0085 | 下一行字符 |
\u 2028 | 行分隔符 |
\u 2029 | 段落分隔符 |
元字符 | 目的 |
---|---|
[乙丙] | 上述任何一项(a、b 或 c) |
[^abc] | 列出的以外的任何其他内容(非 a、b、c) |
[a-zA-Z] | 范围合并(拉丁字符 a 到 z 不区分大小写) |
[广告[mp]] | 字符串联(a 到 d 和 m 到 p) |
[az&&[def]] | 符号的交集(符号 d、e、f) |
[az&&[^bc]] | 减去字符(字符 a、dz) |
元字符 | 目的 |
---|---|
? | 一个或缺失 |
* | 零次或多次 |
+ | 一次或多次 |
{n} | n次 |
{n,} | n次或以上 |
{n,m} | 不少于n次且不多于m次 |
贪婪量词模式
量词的一个特殊功能是能够以不同的模式使用它们:贪婪、超贪婪和惰性。超贪婪模式+
通过在量词后添加符号“ ”开启,惰性模式通过添加符号“ ?
”开启。例如:
"A.+a" // greedy mode
"A.++a" // over-greedy mode
"A.+?a" // lazy mode
使用此模板作为示例,让我们尝试了解量词在不同模式下的工作方式。默认情况下,量词以贪婪模式运行。这意味着它会在字符串中查找最长的可能匹配。运行此代码的结果是:
public static void main(String[] args) {
String text = "Egor Alla Alexander";
Pattern pattern = Pattern.compile("A.+a");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
System.out.println(text.substring(matcher.start(), matcher.end()));
}
}
我们将得到以下输出: Alla Alexa 给定模式“ ”的搜索算法А.+а
按以下顺序执行:
-
在给定的模式中,第一个字符是俄语字母字符
А
。Matcher
从位置零开始,将其与文本的每个字符进行匹配。在文本中的位置 0 处有一个符号Е
,因此Matcher
它会按顺序遍历文本中的字符,直到遇到与模式的匹配项。在我们的示例中,这是位置 5 处的符号。 -
找到与模式的第一个字符的匹配后,
Matcher
它会检查与模式的第二个字符的匹配。在我们的例子中,这是符号“.
”,它代表任何字符。第六位是字母符号
л
。当然,它匹配“任何字符”模式。 -
Matcher
继续检查模式中的下一个字符。在我们的模板中,它是使用“.+
”量词指定的。由于模式中“任意字符”的重复次数为一次或多次,因此Matcher
只要满足“任意字符”条件,它就会依次从字符串中取出下一个字符并检查其是否符合模式,在我们的示例中 - 直到行尾(从文本的第 7 号位置到第 18 号位置)。事实上,
Matcher
它把整条线都抓到了最后——这就是它的“贪婪”体现的地方。 -
Matcher
到达文本末尾并完成对模式的“ ”部分的检查后А.+
,Matcher 开始检查模式的其余部分 - 字母字符а
。由于正向的文本已经结束,因此检查发生在反向,从最后一个字符开始: -
Matcher
“记住”模式“.+
”到达文本末尾时的重复次数,因此它将重复次数减少一并检查文本的模式,直到找到匹配项:
超贪婪量词模式
在超贪婪模式下,匹配器的工作方式与贪婪模式机制类似。不同之处在于,当您将文本抓取到行尾时,不会向后搜索。也就是说,超贪婪模式的前三个阶段将与贪婪模式类似。捕获整个字符串后,匹配器添加模式的其余部分并将其与捕获的字符串进行比较。在我们的示例中,当使用模式“А.++а
”执行 main 方法时,将找不到匹配项。
惰性量词模式
-
在此模式下,在初始阶段,与贪婪模式一样,将寻求与模式的第一个字符的匹配:
-
接下来,它会查找与模式中的下一个字符(任何字符)的匹配项:
-
与贪婪模式不同,惰性模式会搜索文本中的最短匹配,因此在找到与模式的第二个字符(由点指定并与文本中第 6 号位置的字符匹配)的匹配后,
Matcher
将检查文本是否与模式的其余部分匹配 - “а
”字符。 -
由于未找到与文本中的模式匹配的内容(文本中的第 7 位置有符号“ ”
л
),Matcher
因此在模式中添加另一个“任意字符”,因为它被指定为一次或多次,再次将图案与第 5 号到第 8 号位置的文本进行比较: -
在我们的例子中,找到了匹配项,但尚未到达文本末尾。因此,从位置 9 开始,检查首先使用类似的算法搜索模式的第一个字符,然后重复直到文本结尾。
main
当使用“ А.+?а
”模板时,我们将得到以下结果: Alla Alexa 从我们的示例中可以看出,当对同一模板使用不同的量词模式时,我们得到了不同的结果。因此,在搜索时需要考虑到这一特点,根据想要的结果选择所需的模式。
正则表达式中的转义字符
由于 Java 中的正则表达式(或更准确地说其初始表示形式)是使用字符串文字指定的,因此有必要考虑与字符串文字相关的 Java 规范的规则。特别是,\
Java 源代码中字符串文字中的反斜杠字符“”被解释为转义字符,警告编译器后面的字符是特殊字符,必须以特殊方式解释。例如:
String s = "The root directory is \nWindows";//wrap Windows to a new line
String s = "The root directory is \u00A7Windows";//insert paragraph character before Windows
因此,在描述正则表达式并使用“ \
”字符(例如,对于元字符)的字符串文字中,必须将其加倍,以便 Java 字节码编译器不会对其进行不同的解释。例如:
String regex = "\\s"; // template for searching for space characters
String regex = "\"Windows\""; // pattern to search for the string "Windows"
如果我们计划将特殊字符用作“常规”字符,则还应该使用双反斜杠字符来转义特殊字符。例如:
String regex = "How\\?"; // template for searching the string "How?"
Pattern 类的方法
该类Pattern
还有其他处理正则表达式的方法: String pattern()
– 返回创建对象的正则表达式的原始字符串表示形式Pattern
:
Pattern pattern = Pattern.compile("abc");
System.out.println(Pattern.pattern())//"abc"
static boolean matches(String regex, CharSequence input)
– 允许您根据参数中传递的文本检查在 regex 参数中传递的正则表达式input
。返回: true – 如果文本与模式匹配; 假——否则;例子:
System.out.println(Pattern.matches("A.+a","Alla"));//true
System.out.println(Pattern.matches("A.+a","Egor Alla Alexander"));//false
int flags()
– 返回flags
创建时设置的模板参数值,如果未设置该参数则返回0。例子:
Pattern pattern = Pattern.compile("abc");
System.out.println(pattern.flags());// 0
Pattern pattern = Pattern.compile("abc",Pattern.CASE_INSENSITIVE);
System.out.println(pattern.flags());// 2
String[] split(CharSequence text, int limit)
– 将作为参数传递的文本拆分为元素数组String
。该参数limit
确定在文本中搜索的最大匹配数:
- 当–执行匹配
limit>0
搜索;limit-1
- at
limit<0
– 搜索文本中的所有匹配项 - when
limit=0
– 搜索文本中的所有匹配项,同时丢弃数组末尾的空行;
public static void main(String[] args) {
String text = "Egor Alla Anna";
Pattern pattern = Pattern.compile("\\s");
String[] strings = pattern.split(text,2);
for (String s : strings) {
System.out.println(s);
}
System.out.println("---------");
String[] strings1 = pattern.split(text);
for (String s : strings1) {
System.out.println(s);
}
}
控制台输出: Egor Alla Anna -------- Egor Alla Anna下面我们将考虑 另一种用于创建对象的类方法Matcher
。
匹配器类方法
Matcher
是一个类,从中创建对象来搜索模式。Matcher
– 这是一个“搜索引擎”,一个正则表达式的“引擎”。为了进行搜索,他需要获得两件事:搜索模式和搜索“地址”。为了创建对象,Matcher
类中提供了以下方法Pattern
: рublic Matcher matcher(CharSequence input)
作为参数,该方法采用将在其中执行搜索的字符序列。这些是实现接口的类的对象CharSequence
。String
您不仅可以传递, ,还可以传递StringBuffer
, StringBuilder
, Segment
and作为参数CharBuffer
。搜索模板是Pattern
调用该方法的类对象matcher
。创建匹配器的示例:
Pattern p = Pattern.compile("a*b");// compiled the regular expression into a view
Matcher m = p.matcher("aaaaab");//created a search engine in the text “aaaaab” using the pattern "a*b"
现在,在“搜索引擎”的帮助下,我们可以搜索匹配项,找出匹配项在文本中的位置,并使用类方法替换文本。该方法boolean find()
使用该模式在文本中搜索下一个匹配项。使用此方法和循环运算符,您可以根据事件模型分析整个文本(当事件发生时执行必要的操作 - 在文本中查找匹配项)。例如,使用此类的方法,int start()
您int end()
可以确定文本中匹配的位置,并使用方法String replaceFirst(String replacement)
将String replaceAll(String replacement)
文本中的匹配替换为另一个替换文本。例子:
public static void main(String[] args) {
String text = "Egor Alla Anna";
Pattern pattern = Pattern.compile("A.+?a");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
int start=matcher.start();
int end=matcher.end();
System.out.println("Match found" + text.substring(start,end) + " с "+ start + " By " + (end-1) + "position");
}
System.out.println(matcher.replaceFirst("Ira"));
System.out.println(matcher.replaceAll("Olga"));
System.out.println(text);
}
程序输出: 从 5 到 8 个位置找到了匹配的 Alla A 从 10 到 13 个位置找到了安娜匹配 Egor Ira Anna Egor Olga Olga Egor Alla Anna 从示例中可以清楚地看出,这些方法replaceFirst
创建了replaceAll
一个新对象String
- 一个字符串,其中是源文本,其中与模板的匹配项被替换为作为参数传递给方法的文本。此外,该方法replaceFirst
仅替换第一个匹配项,以及replaceAll
测试中的所有匹配项。原文保持不变。其他类方法的使用Matcher
以及正则表达式的示例可以在本系列文章中找到。处理文本时最常见的正则表达式操作来自类Pattern
,并且Matcher
内置于String
. 这些是诸如split
、matches
、replaceFirst
、之类的方法replaceAll
。但事实上,“在幕后”他们使用Pattern
和Matcher
。因此,如果您需要在程序中替换文本或比较字符串而不编写不必要的代码,请使用String
. 如果您需要高级功能,请考虑类Pattern
和Matcher
.
结论
正则表达式在 Java 程序中使用与规则定义的模式匹配的字符串进行描述。当代码运行时,Java 将此字符串重新编译为类对象Pattern
,并使用该类对象Matcher
在文本中查找匹配项。正如我在一开始所说的,正则表达式经常被放在一边以供以后使用,被认为是一个困难的话题。然而,如果您了解语法、元字符、转义的基础知识,并研究正则表达式的示例,您会发现它们比乍一看要简单得多。
GO TO FULL VERSION