正则表达式基础

前言

归纳使用正则表达式的一些基础语法,使用 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 中使用正则表达式会稍微麻烦一些,需要配合 PatternMatcher 两个类一起使用。

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 对匹配到的结果进行了封装,更加符合面向对象编程的思想。

小结

正则表达式这类非常用的知识,每次用的时候都是查语法。对于一些简单的技巧形成自己的归纳总结,可以更快速的解决问题。同时正则表达式的实现非常灵活,同一个内容可能有不同的表达形式,重点还是表达式的正确和完善,不必过于追求表达式是否足够简洁和短。

参考文档

ChatGPT

相关推荐
救救孩子把12 分钟前
深入理解 Java 对象的内存布局
java
落落落sss15 分钟前
MybatisPlus
android·java·开发语言·spring·tomcat·rabbitmq·mybatis
万物皆字节20 分钟前
maven指定模块快速打包idea插件Quick Maven Package
java
夜雨翦春韭27 分钟前
【代码随想录Day30】贪心算法Part04
java·数据结构·算法·leetcode·贪心算法
我行我素,向往自由34 分钟前
速成java记录(上)
java·速成
一直学习永不止步39 分钟前
LeetCode题练习与总结:H 指数--274
java·数据结构·算法·leetcode·数组·排序·计数排序
邵泽明40 分钟前
面试知识储备-多线程
java·面试·职场和发展
程序员是干活的1 小时前
私家车开车回家过节会发生什么事情
java·开发语言·软件构建·1024程序员节
煸橙干儿~~1 小时前
分析JS Crash(进程崩溃)
java·前端·javascript
2401_854391081 小时前
Spring Boot大学生就业招聘系统的开发与部署
java·spring boot·后端