Regex 数字匹配指南 – wiki基地


Regex 数字匹配终极指南:从基础到高级

正则表达式(Regular Expression,简称 Regex 或 Regexp)是处理字符串的强大工具,它能让你以极具灵活性、效率和精确度的方式搜索、匹配、替换或解析文本模式。在各种数据处理场景中,匹配数字是最常见且基础的需求之一。无论是从日志文件中提取数值,验证用户输入,还是解析结构化数据,掌握 Regex 如何匹配数字都是至关重要的技能。

本指南将带你深入了解 Regex 在数字匹配方面的各种技巧,从最基本的数字符号到复杂的浮点数、科学计数法,再到如何在文本中准确捕获数字,以及一些高级应用和注意事项。我们将逐步构建模式,并提供丰富的示例,确保你能够透彻理解并灵活运用。

1. Regex 基础:数字的表示与量词

在深入探讨各种数字类型之前,我们首先需要了解 Regex 中表示数字的最基本元素和控制匹配次数的量词。

1.1 数字字符本身

最简单的方式是直接使用数字字符 09。如果你需要匹配一个特定的数字,比如 7,那么 Regex 模式就是 7。如果你需要匹配一个包含特定数字序列的文本,比如电话号码中的 138,模式就是 138

  • 示例:
    • 文本: “商品编号是 A123B456”
    • 模式: 123
    • 匹配结果: 匹配 “123”

1.2 \d:数字的快捷方式

Regex 提供了一个非常有用的元字符 \d,它代表了任何一个阿拉伯数字,等同于字符集 [0123456789][0-9]。使用 \d 让模式更加简洁易读。

  • 示例:
    • 文本: “我有 3 只猫和 5 只狗”
    • 模式: \d
    • 匹配结果: 分别匹配 “3” 和 “5”

\d 是在大多数编程语言和工具中匹配 0-9 的标准方式。在某些高级或支持 Unicode 的 Regex 引擎中,\d 可能会匹配其他语言的数字字符(如印地语数字),但这通常取决于引擎的配置和模式中的 flags。在绝大多数常见的应用场景下,\d 可以安全地理解为匹配 [0-9]。出于清晰度和兼容性考虑,本指南主要基于匹配 0-9 进行讨论。

1.3 [0-9]:字符集表示

字符集 [] 允许你定义一个需要匹配的字符范围或集合。[0-9] 明确表示匹配从 09 之间的 任何一个 字符。它与 \d 在功能上几乎等同,但有时 [0-9] 会被认为更清晰,因为它直接显示了匹配的字符范围。

  • 示例:
    • 文本: “年份是 2023”
    • 模式: [0-9]
    • 匹配结果: 分别匹配 “2”, “0”, “2”, “3”

1.4 量词:控制数字出现的次数

仅仅匹配单个数字字符是不够的。数字通常由一个或多个数字组成。量词就是用来指定一个字符或模式可以出现多少次的元字符。

  • + (一次或多次): 匹配前一个元素出现一次或多次。

    • \d+ 匹配一个或多个数字字符。这是匹配大多数整数或数字序列的常用方式。
    • 示例:
      • 文本: “订单号:12345,数量:99”
      • 模式: \d+
      • 匹配结果: 匹配 “12345” 和 “99”
  • * (零次或多次): 匹配前一个元素出现零次或多次。

    • \d* 匹配零个或多个数字字符。它会匹配任何数字序列, 包括空字符串。在匹配数字时,通常我们至少需要一位数字,所以 + 更常用。但 * 在匹配可选的数字部分时非常有用。
    • 示例:
      • 文本: “包含数字 123 和空字符串”
      • 模式: \d*
      • 匹配结果: 匹配 “123” 以及 “包含数字 ” 和 ” 和空字符串” 之间的空字符串,以及文本末尾的空字符串。这说明 * 的零次匹配特性需要谨慎使用。
  • ? (零次或一次): 匹配前一个元素出现零次或一次。它使前一个元素成为可选的。

    • \d? 匹配零个或一个数字字符。
    • 示例:
      • 文本: “数字是 5 或 是7”
      • 模式: \d?
      • 匹配结果: 分别匹配 “5”, “7”,以及其他位置的空字符串。
  • {n} (恰好 n 次): 匹配前一个元素恰好出现 n 次。

    • \d{3} 匹配恰好 3 个数字字符。
    • 示例:
      • 文本: “匹配 100 和 2000 但不匹配 10”
      • 模式: \d{3}
      • 匹配结果: 匹配 “100”
  • {n,} (至少 n 次): 匹配前一个元素至少出现 n 次。

    • \d{2,} 匹配至少 2 个数字字符。
    • 示例:
      • 文本: “匹配 12 和 345 但不匹配 6”
      • 模式: \d{2,}
      • 匹配结果: 匹配 “12” 和 “345”
  • {n,m} (至少 n 次,至多 m 次): 匹配前一个元素至少出现 n 次,至多出现 m 次。

    • \d{3,5} 匹配 3 到 5 个数字字符。
    • 示例:
      • 文本: “匹配 123, 4567, 89012 但不匹配 12, 123456”
      • 模式: \d{3,5}
      • 匹配结果: 匹配 “123”, “4567”, “89012”

掌握了 \d 和这些量词,你已经能够构建出匹配整数的基本模式了。

2. 匹配不同类型的数字

数字不仅仅是简单的整数。它们可以是正的、负的、带小数点的、使用科学计数法表示的等等。下面我们将构建更复杂的 Regex 模式来匹配这些不同类型的数字。

2.1 整数 (Integers)

  • 无符号整数 (Positive/Unsigned Integers):
    这是最简单的形式,即一个或多个数字。

    • 模式: \d+
    • 示例:
      • 文本: “商品数量 150,库存 999”
      • 模式: \d+
      • 匹配结果: 匹配 “150”, “999”
  • 带符号整数 (Signed Integers):
    整数前面可能有正号 + 或负号 -。这个符号是可选的 (?),并且它只能是 +- (使用字符集 [-+])。

    • 模式: [-+]?\d+
    • 解释:
      • [-+]: 匹配字符 -+
      • ?: 使前面的 [-+] 出现零次或一次,即符号是可选的。
      • \d+: 匹配一个或多个数字。
    • 示例:
      • 文本: “温度是 +25℃,最低 -5℃”
      • 模式: [-+]?\d+
      • 匹配结果: 匹配 “+25”, “-5”
      • 也能匹配: “100”, “0” (因为符号是可选的)

2.2 浮点数/小数 (Floating-Point Numbers / Decimals)

浮点数通常包含一个整数部分、一个小数点和一个小数部分。匹配浮点数需要考虑几种情况:
1. 整数部分、小数点、小数部分都存在 (e.g., 123.45)
2. 只有整数部分和小数点 (e.g., 123.) – 有些情况允许
3. 只有小数点和小数部分 (e.g., .45) – 有些情况允许
4. 带符号的浮点数 (e.g., -123.45, +.45)

小数点 . 在 Regex 中是一个特殊的元字符,表示匹配 任何字符 (除了换行符)。因此,要匹配字面意义上的小数点,需要对其进行转义,写作 \.

构建一个能够覆盖这些情况的模式需要一些技巧。一个常见的、相对健壮的模式是匹配:(一个或多个数字 跟着 可选的小数部分) 或者 (小数点跟着一个或多个数字)。

  • 模式 (考虑小数点前或后至少有一个数字): [-+]?(\d+\.\d*|\d*\.\d+)

    • 解释:
      • [-+]?: 可选的符号。
      • (...): 这是一个分组。
      • \d+\.\d*: 匹配一个或多个数字 (\d+),跟着一个字面小数点 (\.),再跟着零个或多个数字 (\d*)。这匹配 123., 123.45
      • |: 或。
      • \d*\.\d+: 匹配零个或多个数字 (\d*),跟着一个字面小数点 (\.),再跟着一个或多个数字 (\d+)。这匹配 .45, 123.45
      • 通过 | 组合,模式可以匹配 123.45 (由两部分都能匹配),123. (由第一部分匹配),以及 .45 (由第二部分匹配)。它不会单独匹配 .+-,这是通常期望的行为。
  • 示例:

    • 文本: “价格是 99.50,折扣是 .1,数量是 100.”
    • 模式: [-+]?(\d+\.\d*|\d*\.\d+)
    • 匹配结果: 匹配 “99.50”, “.1”, “100.”
    • 也能匹配: -1.2, +5., -.7
  • 更宽松的模式 (允许 . 单独匹配,通常不建议): [-+]?\d*\.?\d*

    • 解释:
      • [-+]?: 可选符号。
      • \d*: 零个或多个数字 (整数部分)。
      • \.?: 可选的小数点。
      • \d*: 零个或多个数字 (小数部分)。
    • 问题: 这个模式会匹配空字符串,以及单独的 .+-+.-. 等通常不认为是有效数字的组合。所以一般不推荐使用。

在实际应用中,通常需要更精确的匹配。例如,如果要求小数点后必须有数字,或者小数点前必须有数字(除非数字小于1)。

  • 模式 (要求小数点后至少有一个数字,小数点前可选,但不能是空字符串 + 小数点): [-+]?(\d*\.\d+|\d+\.\d*)纠正: 上面的 (\d+\.\d*|\d*\.\d+) 已经包含了这个意思,它要求小数点 任一侧 至少有一位数字,或者两侧都有。让我们坚持使用 [-+]?(\d+\.\d*|\d*\.\d+) 作为标准浮点数模式。

2.3 科学计数法 (Scientific Notation)

科学计数法表示的数字形式为 aEbaeb,其中 a 是一个数字(可以是整数或浮点数),E/e 是指数符号,b 是一个整数(可以是带符号的)。

  • 结构分析:

    • 数字部分 (a): 这可以是之前讨论的整数 [-+]?\d+ 或浮点数 [-+]?(\d+\.\d*|\d*\.\d+)
    • 指数符号: [eE] (匹配字符 eE)。
    • 指数部分 (b): 这是一个带符号的整数 [-+]?\d+
  • 模式 (组合浮点数和指数部分): [-+]?(\d+(\.\d*)?|\.\d+)[eE][-+]?\d+

    • 解释:
      • [-+]?: 可选的数字符号。
      • (\d+(\.\d*)?|\.\d+): 这部分匹配数字 a。它是一个分组,包含了两种情况:
        • \d+(\.\d*)?: 匹配 123123.123.45
        • |: 或。
        • \.\d+: 匹配 .45
        • 注意: 这个内部模式 (\d+(\.\d*)?|\.\d+) 与我们之前讨论的浮点数模式 (\d+\.\d*|\d*\.\d+) 略有不同,但都能有效匹配常见的浮点数形式作为科学计数法的基础。我们选择前者因为它稍微简化了结构,它匹配 123, 123., 123.45, .45,但不匹配 .
      • [eE]: 匹配指数符号 eE
      • [-+]?: 可选的指数符号。
      • \d+: 指数部分的数字 (一个或多个)。
  • 示例:

    • 文本: “常见科学计数法:1.23e-4, -5E+10, 100e3, .5e2, 1.e-1”
    • 模式: [-+]?(\d+(\.\d*)?|\.\d+)[eE][-+]?\d+
    • 匹配结果: 匹配 “1.23e-4”, “-5E+10”, “100e3”, “.5e2”, “1.e-1”

2.4 结合不同类型的数字 (可选整数或浮点数)

有时你需要匹配任何有效的数字,无论是整数还是浮点数。你可以使用 | 操作符将整数模式和浮点数模式结合起来。但是要注意顺序,更具体的模式应该放在前面,否则宽松的模式可能会“吞掉”部分匹配。

  • 浮点数模式: [-+]?(\d+\.\d*|\d*\.\d+)
  • 整数模式: [-+]?\d+

如果直接组合成 [-+]?(\d+\.\d*|\d*\.\d+) | [-+]?\d+,那么 [-+]?\d+ 可能会先匹配到浮点数的整数部分(例如,在 123.45 中匹配 123)。更好的做法是将整数模式作为浮点数模式的一种可选情况或者使用更精炼的模式。

一个能够匹配整数和标准浮点数(要求小数点任一侧有数字)的模式:
* 模式: [-+]?(\d+(\.\d*)?|\.\d+)
* 解释: 这个模式实际上已经能够匹配整数(如 123,由 \d+ 部分匹配)和浮点数(如 123.45, .45, 123., 由 \d+(\.\d*)?|\.\d+ 的不同分支匹配)。所以我们之前用于科学计数法基础的模式 [-+]?(\d+(\.\d*)?|\.\d+) 自身就是一个不错的匹配整数和浮点数的模式!

  • 示例:
    • 文本: “整数 100,浮点数 -1.23,另一个整数 0,另一个浮点数 .5,还有一个 10.”
    • 模式: [-+]?(\d+(\.\d*)?|\.\d+)
    • 匹配结果: 匹配 “100”, “-1.23”, “0”, “.5”, “10.”

如果你还需要包含科学计数法,可以将科学计数法模式也组合进去。注意这里的顺序:科学计数法是最具体的,应该优先考虑。
* 模式 (整数、浮点数、科学计数法): [-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?
* 解释:
* [-+]?: 可选符号。
* (\d+(\.\d*)?|\.\d+): 匹配数字主体部分(整数或浮点数)。
* ([eE][-+]?\d+)?: 使科学计数法部分成为可选的。外部的 ? 使整个科学计数法部分 ([eE][-+]?\d+) 可选。内部的 ([eE][-+]?\d+) 是一个分组,匹配指数符号和指数值。
* 这个模式能够匹配:
* 整数: 123 (\d+ 部分匹配)
* 浮点数: 1.23, .123, 123., 123.45 (\d+(\.\d*)?|\.\d+ 部分匹配)
* 科学计数法: 1.23e4, 1e4, .5e-2, -1.2e+5 (整个模式匹配)

  • 示例:
    • 文本: “数字有 100, -1.23, .5, 10., 1.23e-4, -5E+10”
    • 模式: [-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?
    • 匹配结果: 匹配 “100”, “-1.23”, “.5”, “10.”, “1.23e-4”, “-5E+10”

这是一个相当全面的匹配常见数字格式的模式。

3. 在文本中准确匹配数字:使用锚点和边界

上面的模式可以匹配数字,但它们可能会匹配到字符串中的一部分,或者匹配紧挨着字母的数字(例如,在 “grade12” 中匹配 “12”)。为了在文本中精确地匹配独立的数字,我们需要使用锚点和边界。

3.1 单词边界 \b

\b 是一个零宽度断言(zero-width assertion),它匹配一个单词边界。单词边界出现在以下位置:
* 一个单词字符 (\w,通常是字母、数字、下划线) 和一个非单词字符 (\W) 之间。
* 一个非单词字符和一个单词字符之间。
* 字符串的开头,如果第一个字符是单词字符。
* 字符串的结尾,如果最后一个字符是单词字符。

\b 放在数字模式的两侧,可以确保匹配到的是一个独立的数字,而不是单词的一部分。

  • 模式 (匹配独立的整数): \b\d+\b

    • 示例:
      • 文本: “grade12 售价是 150 元,共 3 件。编号ABC”
      • 模式: \b\d+\b
      • 匹配结果: 匹配 “150”, “3”
      • 不匹配: “12” (因为它紧跟在字母后面)
  • 模式 (匹配独立的浮点数): \b[-+]?(\d+\.\d*|\d*\.\d+)\b

    • 示例:
      • 文本: “温度是 -5.5℃,湿度是 80%,版本是v2.0”
      • 模式: \b[-+]?(\d+\.\d*|\d*\.\d+)\b
      • 匹配结果: 匹配 “-5.5”, “80”
      • 不匹配: “2.0” (因为它紧跟在字母v后面,前面不是单词边界)
  • 模式 (匹配独立的任何常见数字): \b[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?\b

3.2 行/字符串锚点 ^$

  • ^: 匹配输入字符串的开始位置。在多行模式下,也匹配每一行的开头。
  • $: 匹配输入字符串的结束位置。在多行模式下,也匹配每一行的结尾。

使用 ^$ 可以验证整个字符串是否恰好是一个数字,而不是在字符串中查找数字。这在数据验证场景非常有用。

  • 模式 (验证整个字符串是一个整数): ^\d+$

    • 示例:
      • 文本1: “12345”
      • 模式: ^\d+$
      • 匹配结果: 匹配整个字符串 “12345” (成功验证)
      • 文本2: “12345abc”
      • 模式: ^\d+$
      • 匹配结果: 无匹配 (验证失败)
      • 文本3: ” 12345 ” (包含空格)
      • 模式: ^\d+$
      • 匹配结果: 无匹配 (验证失败,因为包含非数字字符空格)
  • 模式 (验证整个字符串是一个带符号的浮点数): ^[-+]?(\d+\.\d*|\d*\.\d+)$

    • 示例:
      • 文本1: “-123.45”
      • 模式: ^[-+]?(\d+\.\d*|\d*\.\d+)$
      • 匹配结果: 匹配整个字符串 “-123.45” (验证成功)
      • 文本2: “123.”
      • 模式: ^[-+]?(\d+\.\d*|\d*\.\d+)$
      • 匹配结果: 匹配整个字符串 “123.” (验证成功,如果你的定义允许这种形式)
      • 文本3: “.5”
      • 模式: ^[-+]?(\d+\.\d*|\d*\.\d+)$
      • 匹配结果: 匹配整个字符串 “.5” (验证成功)
      • 文本4: “abc-1.23”
      • 模式: ^[-+]?(\d+\.\d*|\d*\.\d+)$
      • 匹配结果: 无匹配 (验证失败)
  • 模式 (验证整个字符串是一个整数、浮点数或科学计数法): ^[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?$

使用 \b 用于在文本中提取独立的数字,使用 ^$ 用于验证整个字符串。

4. 高级技巧:分组、捕获与选择性匹配

Regex 的强大之处还在于它的分组和捕获能力,以及更复杂的断言。

4.1 分组与捕获 ()

圆括号 () 用于创建分组。分组有两个主要作用:
1. 将多个元素视为一个整体,以便在其后应用量词或边界。
2. 捕获匹配的文本,以便后续提取或引用(反向引用,Backreferences)。

在数字匹配中,分组常用于:
* 将浮点数的小数部分组合起来使其可选 ((\.\d*)?)。
* 将科学计数法的指数部分组合起来使其可选 (([eE][-+]?\d+)?)。
* 将复杂的数字结构(如 \d+\.\d*|\d*\.\d+)组合起来,在其前后应用符号或边界。
* 捕获数字的特定部分,例如整数部分、小数部分、指数部分。

  • 示例 (捕获整数部分和小数部分): ([-+]?\d+)\.(\d+)

    • 解释:
      • ([-+]?\d+): 第一个捕获分组,匹配并捕获带符号的整数部分。
      • \.: 匹配小数点。
      • (\d+): 第二个捕获分组,匹配并捕获小数部分的数字。
    • 示例:
      • 文本: “坐标是 -10.5, 25.75”
      • 模式: ([-+]?\d+)\.(\d+)
      • 匹配结果1: 匹配 “-10.5″。第一组捕获 “-10″,第二组捕获 “5”。
      • 匹配结果2: 匹配 “25.75”。第一组捕获 “25”,第二组捕获 “75”。
  • 示例 (捕获科学计数法的组成部分): ([-+]?(\d+(\.\d*)?|\.\d+))([eE]([-+]?\d+))

    • 解释:
      • ([-+]?(\d+(\.\d*)?|\.\d+)): 第一个捕获分组,匹配并捕获整个数字主体部分 (e.g., 1.23, -5, .7).
        • 注意内部还有嵌套的分组,它们也会被捕获(取决于引擎,通常是从左到右计数)。
      • [eE]: 匹配指数符号。
      • ([-+]?\d+): 第二个捕获分组 (整个模式的第四个捕获分组,如果计算嵌套的话),匹配并捕获指数部分 (e.g., -4, +10, 3).
    • 示例:
      • 文本: “科学计数法:1.23e-4, -5E+10”
      • 模式: ([-+]?(\d+(\.\d*)?|\.\d+))([eE]([-+]?\d+))
      • 匹配结果1: 匹配 “1.23e-4″。
        • Group 1: “1.23”
        • Group 2: “1.23” (取决于引擎,可能与 Group 1 重复或捕获更内层)
        • Group 3: “.23” (或空字符串)
        • Group 4: “e-4”
        • Group 5: “-4”
      • 匹配结果2: 匹配 “-5E+10″。
        • Group 1: “-5”
        • Group 2: “-5”
        • Group 3: “”
        • Group 4: “E+10”
        • Group 5: “+10”

4.2 非捕获分组 (?:...)

如果你只需要分组来应用量词或结构化模式,但不需要捕获分组内的文本,可以使用非捕获分组 (?:...)。这可以提高一点性能,并避免在结果中出现不必要的捕获组。

  • 模式 (匹配浮点数,不捕获内部细节): [-+]?(?:\d+\.\d*|\d*\.\d+)
    • 这里 (?:\d+\.\d*|\d*\.\d+) 作为一个整体应用 [-+]? 符号,但 \d+\.\d*\d*\.\d+ 的匹配内容本身不会被捕获到结果中(除非整个模式被捕获)。

4.3 前后查找 (Lookarounds)

前后查找是零宽度断言,它们匹配位置而不是字符。它们断言在当前位置的前面(后查找)或后面(前查找)是否存在(正向)或不存在(负向)特定的模式。它们不会消耗字符,也不会包含在最终匹配结果中。

  • 肯定前查找 (?=...): 要求后面跟着的模式必须匹配。

    • 示例 (匹配后面跟着 “%” 的数字): \d+(?=%)
      • 解释: 匹配一个或多个数字 \d+,但只在它们后面紧跟着字符 % 的情况下。% 本身不包含在匹配结果中。
      • 文本: “完成度 80%,剩余 20%。价格 100元。”
      • 模式: \b\d+(?=\%)\b (加上边界更精确)
      • 匹配结果: 匹配 “80”, “20”
  • 否定前查找 (?!...): 要求后面跟着的模式不能匹配。

    • 示例 (匹配后面不跟着字母的数字): \d+\b(?![a-zA-Z])
      • 解释: 匹配以单词边界结尾的数字,但这个数字后面不能是字母。可以用来避免匹配像 “grade12” 中的 “12” (如果 \b2 后面)。通常 \b 本身已经处理了这种情况,但负向断言提供了更精细的控制。
      • 文本: “version1.0 grade12 value 100”
      • 模式: \b\d+\b(?![a-zA-Z])
      • 匹配结果: 匹配 “100” (因为后面是空格)
      • 不匹配: “1” (在 “version1.0” 中), “12” (在 “grade12” 中)
  • 肯定后查找 (?<=...): 要求前面跟着的模式必须匹配。

    • 示例 (匹配前面跟着 “$” 的数字): (?<=\$)\d+
      • 解释: 匹配一个或多个数字 \d+,但只在它们前面紧跟着字符 $ 的情况下。$ 本身不包含在匹配结果中。需要转义 $
      • 文本: “价格:$100 和 ¥50”
      • 模式: (?<=\$)\d+
      • 匹配结果: 匹配 “100”
  • 否定后查找 (?<!...): 要求前面跟着的模式不能匹配。

    • 示例 (匹配前面不跟着负号的数字): (?<!-)\b\d+\b
      • 解释: 匹配独立的数字,但前面不能紧跟着 -。可以用来匹配正整数,同时排除负整数。
      • 文本: “数字有 100, -50, +20, 0”
      • 模式: (?<!-)\b\d+\b
      • 匹配结果: 匹配 “100”, “+20”, “0”
      • 不匹配: “-50”

前后查找使得根据数字 周围的上下文 进行匹配成为可能,而不必将上下文包含在实际匹配结果中。这对于提取特定语境下的数字非常有用。

5. 处理国际化和特定格式

在实际应用中,数字的表示可能因地区而异(例如,小数点是 , 而不是 .)。此外,特定的数字格式(如货币、电话号码、邮政编码)虽然基于数字,但有固定的结构。

5.1 小数点和千位分隔符

在某些地区,逗号 , 用作小数点,点 . 用作千位分隔符(或反之)。标准的 \d+\.\d* 模式将不适用。

  • 模式 (匹配使用逗号作为小数点的浮点数): [-+]?(\d+,\d*|\d*,\d+)

    • 示例: 123,45, ,50, 123,
  • 模式 (匹配使用点作为小数点的浮点数): [-+]?(\d+\.\d*|\d*\.\d+) (我们之前的模式)

  • 模式 (匹配使用点或逗号作为小数点的浮点数): [-+]?(\d+[.,]\d*|\d*[.,]\d+)

    • 解释: 使用字符集 [.,] 来匹配点或逗号作为小数点。
    • 示例: “值是 10.5 或 20,75”
    • 模式: \b[-+]?(\d+[.,]\d*|\d*[.,]\d+)\b
    • 匹配结果: 匹配 “10.5”, “20,75”

处理千位分隔符会使 Regex 模式变得更复杂。例如,匹配形如 1,234,567.891.234.567,89 的数字:
* 模式 (美式千位分隔符 , 和小数点 .): \b[-+]?\d{1,3}(,\d{3})*(\.\d+)?\b
* 解释:
* \b[-+]?: 边界和可选符号。
* \d{1,3}: 匹配开头 1 到 3 位数字 (e.g., 1, 12, 123).
* (,\d{3})*: 匹配零个或多个由 , 跟着 恰好 3 个数字组成的组 (e.g., ,234, ,567).
* (\.\d+)?: 可选的小数部分 (. 跟着一个或多个数字)。
* \b: 边界。
* 示例: “金额: 1,234,567.89 和 999”
* 模式: \b[-+]?\d{1,3}(,\d{3})*(\.\d+)?\b
* 匹配结果: 匹配 “1,234,567.89” 和 “999”

处理同时支持多种千位分隔符和 Decimal Separators 的情况,或者非常规的数字格式,可能会导致 Regex 模式极其复杂且难以维护。在这种情况下,更推荐的方式是:
1. 使用 Regex 匹配一个大致的数字模式(例如,包含数字、小数点、逗号、正负号的序列)。
2. 使用编程语言的代码进一步解析和验证匹配到的字符串,移除分隔符,转换为标准数值类型。

5.2 特定格式的数字

电话号码、IP 地址、信用卡号等是具有特定结构的数字序列。匹配它们通常不仅仅是匹配数字本身,还需要匹配连接符、空格或固定的位数。

  • 示例 (简单中国座机号码,带区号,如 010-12345678): \d{3,4}-\d{7,8}

    • 解释: 匹配 3 或 4 位数字 (\d{3,4}),跟着一个连字符 -,再跟着 7 或 8 位数字 (\d{7,8})。
  • 示例 (简单 IPv4 地址,如 192.168.1.1): \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}

    • 解释: 匹配 1 到 3 位数字 (\d{1,3}),跟着一个点 \.,重复四次。
    • 注意: 这个模式会匹配无效的 IP 地址,如 999.999.999.999。要精确匹配有效的 IP 地址(每段在 0-255 之间),Regex 会变得非常复杂,通常需要 ((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?) 这样的模式,这超出了纯粹的数字匹配范围,涉及到更复杂的数字范围逻辑。

对于特定格式的数字,模式是基于其 固定结构 来构建的,数字匹配只是其中的一个组成部分。

6. 性能与注意事项

  • 复杂度: 复杂的 Regex 模式可能会降低性能,尤其是在处理大量文本时。嵌套分组、大量的回溯(backtracking)都可能导致性能问题。
  • 回溯: 量词默认是“贪婪的”(greedy),它们会尽可能多地匹配字符。这可能导致引擎在匹配失败后进行大量回溯。在数字匹配中,这通常不是一个大问题,但了解贪婪与非贪婪 (+?, *?, ??, {n,m}?) 的区别在某些场景下可能有用(尽管在标准数字模式中很少用到)。
  • 明确性: 对于简单的数字,如整数,使用 \d+[0-9]+ 更简洁。但对于复杂的小数或科学计数法,清晰地写出每个部分的模式并适当使用分组非常重要。
  • 过度使用 Regex: Regex 擅长模式匹配,但不擅长数值计算或复杂的数值验证(例如,检查一个数字是否在某个范围内,或者计算校验和)。对于这些任务,应该在匹配到数字字符串后,使用编程语言的数值处理功能。
  • 测试: 总是用各种有效的和无效的数字示例来测试你的 Regex 模式,包括边界情况(如 0, -0, .5, 1., 1e0, 1e-1, +1e+1)。

7. 总结

掌握 Regex 中的数字匹配是高效处理文本数据的基石。本指南带你回顾了:

  • 基本元素: 0-9, \d, [0-9]
  • 核心工具: 量词 +, *, ?, {n,m}
  • 不同数字类型: 构建模式匹配整数、浮点数和科学计数法。
  • 精确定位: 使用 \b 边界和 ^, $ 锚点在文本中查找或验证数字。
  • 高级特性: 利用分组 () 进行结构化和捕获,使用前后查找 (?=), (?!), (?<=), (?<!) 根据上下文匹配。
  • 实际考虑: 处理国际化的小数点/分隔符,以及匹配特定格式的数字。
  • 重要提醒: 注意模式的复杂度、性能,以及何时应该结合编程语言进行处理。

Regex 数字匹配的模式可以从简单的 \d+ 扩展到非常复杂的组合。关键在于理解每种 Regex 元素的作用,并根据具体需求(要匹配哪种数字类型?它们出现在什么上下文?需要验证整个字符串吗?需要捕获特定部分吗?)来构建合适的模式。

最好的学习方法是实践。尝试在在线 Regex 测试工具(如 Regex101, RegExr)中输入不同的文本和模式,观察匹配结果,修改模式,直到它符合你的预期。随着经验的积累,你将能够快速准确地构建出满足需求的数字匹配模式。

希望这篇详细指南能帮助你全面掌握 Regex 的数字匹配艺术!


发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部