正则表达式-手机号验证

69 阅读4分钟

正则表达式(Scala 版)全解析

一、正则表达式的定义、作用、应用场景

1. 定义

正则表达式(Regular Expression,简称 Regex/RE)是一种描述文本模式的语法规则,本质是一串特殊字符组成的 “匹配模板”,用于匹配、查找、替换、校验字符串。Scala 中没有独立的正则语法,复用 Java 的正则引擎,同时提供了更简洁的语法糖(如.r方法、模式匹配集成)。

2. 核心作用

  • 匹配校验:验证字符串是否符合指定格式(如手机号、邮箱、身份证);
  • 查找提取:从文本中提取符合规则的子串(如从日志中提取所有 IP 地址);
  • 替换修改:批量替换文本中符合规则的内容(如替换所有敏感词、格式化字符串);
  • 分割切分:按指定模式分割字符串(如按 “任意空白符” 分割文本)。

3. 典型应用场景

场景示例
数据校验校验手机号、邮箱、密码复杂度
日志分析从 Nginx 日志中提取请求 URL、响应状态码
文本清洗去除文本中的特殊符号、多余空格
爬虫数据提取从 HTML 中提取标题、价格、链接
配置文件解析解析.properties/.yml 中的规则配置

二、正则表达式的组成部分

正则表达式由原子量词边界符修饰符分组 / 断言五类核心元素组成:

1. 原子(最基础的匹配单元)

是正则的最小组成单位,代表 “匹配什么字符”,分为以下类型:

类型示例说明
普通字符a1@匹配自身(如abc匹配字符串 "abc")
预定义字符类\d\w\s匹配一类字符(如\d匹配任意数字)
自定义字符集[0-9][a-z]匹配集合内任意一个字符
转义字符.*匹配特殊符号(如.匹配点号,需转义)

2. 量词(控制原子的匹配次数)

用于指定 “原子重复匹配多少次”,必须跟在原子 / 分组后:

量词说明示例
*匹配 0 次或多次(贪婪)a* 匹配 ""、"a"、"aaa"
+匹配 1 次或多次(贪婪)a+ 匹配 "a"、"aaa"(不匹配 "")
?匹配 0 次或 1 次a? 匹配 ""、"a"
{n}精确匹配 n 次a{3} 匹配 "aaa"
{n,}匹配 n 次及以上a{2,} 匹配 "aa"、"aaa"
{n,m}匹配 n 到 m 次(包含 n 和 m)a{2,5} 匹配 "aa" 到 "aaaaa"

3. 边界符(限定匹配位置)

用于指定 “匹配的字符串在文本中的位置”:

边界符说明示例
^匹配字符串开头^abc 匹配以 "abc" 开头的字符串
$匹配字符串结尾xyz$ 匹配以 "xyz" 结尾的字符串
\b匹配单词边界(非单词字符)\bhello\b 匹配独立的 "hello"

4. 修饰符(全局规则)

Scala 中通过Regex的配置指定,控制匹配的全局行为:

修饰符说明Scala 中使用方式
i忽略大小写"(abc)".r.unanchored(或结合(?i)
s单行模式(.匹配换行)"(?s)a.b".r
m多行模式(^/$匹配行首 / 行尾)"(?m)^line".r

5. 分组与断言(高级特性)

类型示例说明
捕获分组(abc)把多个原子视为一个整体,可提取匹配结果
非捕获分组(?:abc)分组但不捕获结果(性能更高)
正向断言(?=abc)匹配 “后面跟着 abc” 的位置(不占字符)
反向断言(?!abc)匹配 “后面不跟着 abc” 的位置

三、正则表达式的核心规则(Scala 常用)

1. 基础字符匹配规则

规则含义Scala 示例
\d匹配任意数字(等价于[0-9]"""\d""".r.findFirstIn("a1b") → Some("1")
\D匹配非数字"""\D""".r.findFirstIn("123a") → Some("a")
\w匹配单词字符(0-9/A-Z/a-z/_)"""\w""".r.findFirstIn("a_@") → Some("a")
\W匹配非单词字符"""\W""".r.findFirstIn("a_@") → Some("@")
\s匹配空白字符(空格 / 制表符 / 换行)"""\s""".r.findFirstIn("a b") → Some(" ")
\S匹配非空白字符"""\S""".r.findFirstIn(" a ") → Some("a")
.匹配任意字符(除换行,单行模式可匹配)""".""".r.findFirstIn("a\n") → Some("a")
[abc]匹配 a、b、c 中的任意一个"""[abc]""".r.findFirstIn("xby") → Some("b")
[^abc]匹配非 a、b、c 的任意字符"""[^abc]""".r.findFirstIn("xby") → Some("x")
[a-z]匹配 a 到 z 的小写字母"""[a-z]""".r.findFirstIn("A1b") → Some("b")

2. 量词规则(贪婪 / 非贪婪)

  • 贪婪匹配:默认行为,尽可能匹配更多字符(如a.*b匹配 "a123b456b" 会匹配整个 "a123b456b");
  • 非贪婪匹配:量词后加?,尽可能匹配更少字符(如a.*?b匹配 "a123b456b" 会匹配 "a123b")。

3. Scala 特有的正则规则

  • Scala 字符串中``是转义符,正则中的\d需写为\d
  • 通过.r方法将字符串转为Regex对象(核心语法糖);
  • 支持模式匹配中直接使用正则。

四、Scala 中正则表达式的应用案例

以下案例基于 Scala 标准库scala.util.matching.Regex,覆盖常见场景:

案例 1:手机号校验

需求:校验字符串是否为合法手机号(1 开头,第二位 3-9,共 11 位数字)

scala

import scala.util.matching.Regex

object RegexDemo {
  def main(args: Array[String]): Unit = {
    // 定义正则表达式(注意双反斜杠)
    val phonePattern: Regex = "^1[3-9]\d{9}$".r
    
    // 待校验的手机号
    val phones = List("13812345678", "12812345678", "1381234567", "138123456789")
    
    // 校验逻辑
    phones.foreach { phone =>
      phonePattern.findFirstIn(phone) match {
        case Some(_) => println(s"$phone 是合法手机号")
        case None => println(s"$phone 是非法手机号")
      }
    }
  }
}

输出

plaintext

13812345678 是合法手机号
12812345678 是非法手机号
1381234567 是非法手机号
138123456789 是非法手机号

案例 2:邮箱提取

需求:从文本中提取所有合法邮箱地址

scala

object RegexDemo {
  def main(args: Array[String]): Unit = {
    // 邮箱正则:用户名@域名(简化版)
    val emailPattern = """\w+@\w+.\w+""".r
    val text = "联系我们:support@example.com 或 sales@company.cn,电话123456"
    
    // 提取所有匹配的邮箱
    val emails = emailPattern.findAllIn(text).toList
    println("提取的邮箱:" + emails) // 输出:List(support@example.com, sales@company.cn)
  }
}

案例 3:字符串替换

需求:将文本中的所有数字替换为*

scala

object RegexDemo {
  def main(args: Array[String]): Unit = {
    val numPattern = """\d""".r
    val text = "订单号:123456,金额:999元"
    val replaced = numPattern.replaceAllIn(text, "*")
    println(replaced) // 输出:订单号:******,金额:***元
  }
}

案例 4:模式匹配中使用正则

需求:根据字符串格式(手机号 / 邮箱 / 普通文本)分类处理

scala

object RegexDemo {
  def main(args: Array[String]): Unit = {
    val phonePattern = "^1[3-9]\d{9}$".r
    val emailPattern = """\w+@\w+.\w+""".r
    
    def classifyString(str: String): String = str match {
      case phonePattern() => "手机号"
      case emailPattern() => "邮箱"
      case _ => "普通文本"
    }
    
    println(classifyString("13812345678")) // 手机号
    println(classifyString("test@example.com")) // 邮箱
    println(classifyString("hello world")) // 普通文本
  }
}

案例 5:复杂分组提取(日志解析)

需求:从 Nginx 日志行中提取 IP、请求方法、URL

scala

object RegexDemo {
  def main(args: Array[String]): Unit = {
    // Nginx日志行示例:192.168.1.1 - - [10/Oct/2025:12:34:56 +0800] "GET /index.html HTTP/1.1" 200 1234
    val nginxPattern = """(\d+.\d+.\d+.\d+) .* "(\w+) (/\S+) """.r
    
    val logLine = "192.168.1.1 - - [10/Oct/2025:12:34:56 +0800] "GET /index.html HTTP/1.1" 200 1234"
    
    logLine match {
      case nginxPattern(ip, method, url) =>
        println(s"IP: $ip, 方法: $method, URL: $url")
      case _ =>
        println("日志格式不匹配")
    }
  }
}

输出

plaintext

IP: 192.168.1.1, 方法: GET, URL: /index.html

总结

Scala 中的正则表达式核心是复用 Java 正则引擎,通过.r方法简化使用,重点掌握:

  1. 基础规则(\d/\w/ 量词 / 边界符);
  2. 字符串中转义符\的使用;
  3. findFirstIn/findAllIn/replaceAllIn等核心方法;
  4. 模式匹配与正则的结合。实际开发中,优先使用简化版正则满足需求,复杂场景(如 URL/HTML 解析)可结合专用库(如 jsoup)提升效率。