杰瑞科技汇

java double 正则表达式

下面我将从基础到高级,详细讲解如何编写和使用正则表达式来匹配、验证和提取 double 字符串。

java double 正则表达式-图1
(图片来源网络,侵删)

核心正则表达式

一个 double 字符串通常由以下几个部分组成:

  1. 可选的正负号: 或 。
  2. 整数部分:一个或多个数字 (0-9)。
  3. 可选的小数部分
    • 一个点号 。
    • 后面跟着零个或多个数字。
    • 注意:根据需求,小数点后至少需要有一位数字( 是不合法的 double 字符串,而 0 是合法的),或者允许没有数字( 合法)。
  4. 可选的科学计数法
    • 字母 eE
    • 后面跟着一个可选的正负号 ( 或 )。
    • 最后跟着一个或多个数字(指数部分)。

基础版本(最常用)

这个版本匹配绝大多数标准的 double 格式,包括科学计数法,并且要求小数点后至少有一位数字。

[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?

分解解释:

部分 正则表达式 解释
可选符号 [-+]? 匹配一个可选的 或 。 表示零次或一次。
整数部分 [0-9]* 匹配零个或多个数字,这允许像 .123 这样的数字。
小数点 \.? 匹配一个可选的点号 ,必须用 \ 转义,因为 在正则中有特殊含义(匹配任意字符)。
小数部分 [0-9]+ 匹配一个或多个数字,这确保了如果有点号,后面至少有一位数字(45.45 都可以,但 不行)。
科学计数法 (整体) ([eE][-+]?[0-9]+)? 整个科学计数法部分是可选的(最外层的 )。
   e/E [eE] 匹配 eE
   指数符号 [-+]? 匹配指数部分可选的 或 。
   指数数字 [0-9]+ 匹配一个或多个数字作为指数。

这个正则表达式可以匹配以下示例:

java double 正则表达式-图2
(图片来源网络,侵删)
  • 456
  • -123.456
  • +123.456
  • .456
  • 123
  • 23e10
  • 23E-10
  • .456E+10

它不能匹配:

  • (只有小数点)
  • e10 (没有底数)
  • 2.3 (多个小数点)

Java 代码实现

在 Java 中,我们主要使用 java.util.regex 包中的 PatternMatcher 类。

示例 1:验证一个字符串是否是合法的 double

这是最常见的用法,例如在表单输入验证中。

import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class DoubleRegexExample {
    public static void main(String[] args) {
        // 定义正则表达式
        String doubleRegex = "[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?";
        // 要测试的字符串数组
        String[] testStrings = {
            "123.45", "-123.45", "+123.45", ".456", "123.", "123",
            "1.23e10", "1.23E-10", ".456E+10", // 合法
            ".", "e10", "1.2.3", "abc", "123e"   // 非法
        };
        // 编译正则表达式
        Pattern pattern = Pattern.compile(doubleRegex);
        for (String testStr : testStrings) {
            Matcher matcher = pattern.matcher(testStr);
            if (matcher.matches()) {
                System.out.printf("'%s' 是一个合法的 double 字符串。%n", testStr);
            } else {
                System.out.printf("'%s' 不是一个合法的 double 字符串。%n", testStr);
            }
        }
    }
}

示例 2:从一段文本中提取所有 double

假设你有一段混合了文本和数字的文本,你需要把所有的 double 都找出来。

import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class DoubleExtractorExample {
    public static void main(String[] args) {
        String text = "温度是 25.5 度,压力为 1.2e3 帕,错误值包括 . 和 123e,有效值还有 -0.5 和 +99.9。";
        // 使用与上面相同的正则表达式
        String doubleRegex = "[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?";
        Pattern pattern = Pattern.compile(doubleRegex);
        Matcher matcher = pattern.matcher(text);
        System.out.println("从文本中提取到的 double 值:");
        while (matcher.find()) {
            // matcher.group() 返回匹配到的子字符串
            System.out.println(matcher.group());
        }
    }
}

输出:

从文本中提取到的 double 值:
25.5
1.2e3
-0.5
+99.9

进阶:更严格的正则表达式

根据你的具体需求,你可能需要更严格的规则。

版本 A:不允许像 .123 或 这样的格式

要求整数部分和小数部分必须至少有一个存在。

[-+]?([0-9]+(\.[0-9]*)?|\.[0-9]+)([eE][-+]?[0-9]+)?

解释: ([0-9]+(\.[0-9]*)?|\.[0-9]+) 这部分是关键,它表示:

  • 情况1[0-9]+(\.[0-9]*)? - 一个或多个数字,后面可以跟着一个点号和零个或多个数字(123, , 45)。
  • 或者\| - 逻辑或。
  • 情况2\.[0-9]+ - 一个点号后面跟着一个或多个数字(.45)。

这样, 和 .456 都能匹配,但单独的 不能。

版本 B:不允许 这样的格式(点号后必须有数字)

这是最严格的 double 数值格式。

[-+]?[0-9]+\.[0-9]+([eE][-+]?[0-9]+)?

解释: 这个正则表达式要求必须有一个整数部分 ([0-9]+),然后是一个点号 (\.),然后必须有一个小数部分 ([0-9]+)。

它不能匹配:

  • 123
  • .456

重要注意事项

String.matches() vs Pattern.matcher().matches()

String 类有一个方便的 matches() 方法,它内部会自动将整个字符串与正则表达式进行匹配(相当于在正则表达式前后添加了 ^ 和 )。

String str = "123.45";
boolean isDouble = str.matches("[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?"); // 返回 true

这完全等同于我们示例1中的 pattern.matcher(str).matches()

使用 ^ 和 明确边界

为了确保整个字符串都符合规则,而不仅仅是其中一部分,最好在正则表达式的开头加上 ^(表示字符串开始),结尾加上 (表示字符串结束)。

^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$

用这个正则去匹配 "123.45 is a number"matches() 方法会返回 false,因为它期望整个字符串都匹配,而不仅仅是前半部分。

性能考虑

对于简单的验证,String.matches() 非常方便,如果你需要在同一个 Pattern 对象上对多个字符串进行匹配(如示例2中的循环),那么预先编译 Pattern 对象(使用 Pattern.compile())会得到更好的性能,因为它避免了重复编译正则表达式带来的开销。

Double.parseDouble() 的局限性

请记住,正则表达式只负责验证字符串的格式,一个字符串可能通过了正则匹配,但在转换为 double 时仍然可能抛出 NumberFormatException

  • 科学计数法中的指数部分太大或太小(超出 double 的表示范围)。
  • 数字太长,导致精度丢失或溢出。

最可靠的最终验证方式仍然是 try-catch 块:

public static boolean isValidDouble(String str) {
    // 1. 先用正则进行快速格式过滤
    if (!str.matches("^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$")) {
        return false;
    }
    // 2. 再用 Double.parseDouble() 进行最终验证
    try {
        Double.parseDouble(str);
        return true;
    } catch (NumberFormatException e) {
        return false;
    }
}

这个结合了正则和 try-catch 的方法是最健壮的,正则表达式可以过滤掉大部分明显不符合格式的字符串,而 parseDouble 则处理了数值范围等更深层次的问题。

分享:
扫描分享到社交APP
上一篇
下一篇