前言
归纳使用正则表达式的一些基础语法,使用 AI 生成的代码时,可以了解大致的逻辑,分辨出其中错误,并加以修改。
随着大模型产品的火热,日常写代码的时候也非常依赖 AI 帮忙生成代码。大模型有一个命门就是胡说八道,这也可以说是他能这么厉害的根基。因此,有时候生成的代码是基于不同类型的语言融合之后的结果,如果使用者对编程语言不熟悉,或者对 API 不是很了解,难免会被 AI 带到沟里去。
最近在使用 AI 生成正则表达式的时候,就遇到多次被坑的情况。究其原因还是对正则表达式基础语法的不了解,盲目信从 AI 生成的代码,在不断试错的过程中反而浪费了不少时间。下面对正则表达式的基础语法做一总结,方便后续使用时可以对照排查,方便验证和解决问题。
正则表达式基础知识
正则表达式(Regular Expression,简称Regex)是一种用于字符串搜索和操作的强大工具。
基本字符
- 普通字符 :直接表示其自身,如
abc
匹配 "abc"。 - 特殊字符 :具有特殊含义的字符,如
.
、*
、+
、?
等。
特殊字符和元字符
| 特殊字符 | 描述 |
|------|-------------|----------|
| .
| 任意单个字符(非换行) |
| ^
| 字符串的开始 |
| $
| 字符串的结束 |
| *
| 前面元素零次或多次 |
| +
| 前面元素一次或多次 |
| ?
| 前面元素零次或一次 |
| ` | ` | 逻辑或,分隔选项 |
| []
| 字符集,匹配括号内任意 |
| ()
| 分组和捕获 |
量词
量词 | 描述 |
---|---|
{n} |
精确出现n次 |
{n,} |
至少出现n次 |
{n,m} |
出现n到m次 |
字符类
字符类 | 描述 |
---|---|
\d |
数字 [0-9] |
\D |
非数字 [^0-9] |
\w |
单词字符 [A-Za-z0-9_] |
\W |
非单词字符 [^A-Za-z0-9_] |
\s |
空白字符 |
\S |
非空白字符 |
修饰符
i
:忽略大小写。g
:全局匹配。m
:多行匹配。
示例
\d{3}-\d{2}-\d{4}
:匹配电话号码。^https?://
:匹配以 "http" 或 "https" 开始的URL。[a-zA-Z]
:匹配任何单个字母。\bhe\w*
:匹配以 "he" 开始的单词。
使用正则表达式
下面以正则表达式
regex
[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[a-z]{2,6}
为例(匹配 xxx@yyy 类型的邮箱),看看正则表达式的用法。
kotlin
val emailRegex = Regex("[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[a-z]{2,6}")
- matches 完全匹配
kotlin
val text = "Please contact us at support@example.com or sales@example.com."
println(emailRegex.matches(text))
println(emailRegex.matches("yingkongshi11@gmail.com"))
shell
false
true
- find 第一个匹配的项
kotlin
val matchResult = emailRegex.find(text)
println("matchResult ${matchResult?.value}")
println("group ${matchResult?.groups}")
println(matchResult?.groups?.get(0))
shell
matchResult support@example.com
group [MatchGroup(value=support@example.com, range=21..39)]
MatchGroup(value=support@example.com, range=21..39)
- findAll 所有匹配的项
kotlin
val matchAllResult = emailRegex.findAll(text)
matchAllResult.forEach {
println(it.value)
println(it.range)
println(it.groups)
println(it.groupValues)
println("=========================")
}
shell
// val matchAllResult: Sequence<MatchResult>
support@example.com
21..39
[MatchGroup(value=support@example.com, range=21..39)]
[support@example.com]
=========================
sales@example.com
44..60
[MatchGroup(value=sales@example.com, range=44..60)]
[sales@example.com]
=========================
需要注意的是
-
这里 findAll 返回的并不是列表,而是一个 Sequence 。
-
find/fidnAll 方法默认都是从第一个字符开始匹配,实际调用时可以基于需要传入合适的位置,koltin 默认参数真是太妙了。
-
replace 直接替换
kotlin
val newResult = emailRegex.replace(text, "O(∩_∩)O哈哈~")
println(newResult)
val newnewResult = emailRegex.replace(text) { r ->
val sb = StringBuilder()
sb.append(r.value.uppercase(Locale.getDefault()))
sb
}
println(newnewResult)
val result1 = emailRegex.replaceFirst(text, "_(:з」∠)_ogo")
println(result1)
shell
//val newResult: String
Please contact us at O(∩_∩)O哈哈~ or O(∩_∩)O哈哈~.
val newnewResult: String
Please contact us at SUPPORT@EXAMPLE.COM or SALES@EXAMPLE.COM.
//val result1: String
Please contact us at _(:з」∠)_ogo or sales@example.com.
可以用 regex 对象直接替换符合正则表达式的内容,不必自己获取位置后,在手动进行 replace。
- 在 Java 中使用
在 Java 中使用正则表达式会稍微麻烦一些,需要配合 Pattern
和 Matcher
两个类一起使用。
java
public class MatterTest {
public static void main(String[] args) {
String emailRegex = "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[a-z]{2,6}";
Pattern pattern = Pattern.compile(emailRegex);
String email2 = "please contact us at example@example.com or bbc@136.com or cnn@kk.com";
Matcher matcher2 = pattern.matcher(email2);
while (matcher2.find()) {
String info = String.format(Locale.getDefault(), "find result %20s,start from %3d,end at %3d", matcher2.group(), matcher2.start(), matcher2.end());
System.out.println(info);
}
}
}
在 Java 中 find() 返回的是 boolean 值,表示是否找到匹配的内容,因此在包含多个内时,可以进行多个匹配项的查找。
shell
total match-1 true
total match-2 false
find result example@example.com,start from 21,end at 40
find result bbc@136.com,start from 44,end at 55
find result cnn@kk.com,start from 59,end at 69
可以看到这里通过 while 循环返回的结果其实和 findAll 类似,只不过在 kotlin 中,通过 Matcher 对匹配到的结果进行了封装,更加符合面向对象编程的思想。
小结
正则表达式这类非常用的知识,每次用的时候都是查语法。对于一些简单的技巧形成自己的归纳总结,可以更快速的解决问题。同时正则表达式的实现非常灵活,同一个内容可能有不同的表达形式,重点还是表达式的正确和完善,不必过于追求表达式是否足够简洁和短。