Java 正则表达式:比你想象的更强大

Java 正则表达式:比你想象的更强大

正则表达式是每一位开发者都应该掌握的技能,但你知道吗,在 Java 中,正则表达式的处理能力远超过你的想象。今天,我们不单纯讲解正则表达式的语法,而是通过具体的编码实验,对比不同正则表达式方案的性能和功能差异,帮助你深刻理解 Java 正则表达式的强大之处。

实验 1:简单匹配

假设你需要验证一个字符串是否包含特定的子字符串,比如检查一个 URL 是否包含 ".com"。你会选择什么样的方法呢?让我们看看两种方案的对比。

方案 1:使用 String.contains() 方法

java 复制代码
public class TestContains {
    public static void main(String[] args) {
        String url = "https://www.example.com";
        boolean contains = url.contains(".com"); // 简单的子字符串匹配
        System.out.println("Contains .com? " + contains);
    }
}

方案 2:使用正则表达式 Pattern 和 Matcher

java 复制代码
import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class TestRegex {
    public static void main(String[] args) {
        String url = "https://www.example.com";
        Pattern pattern = Pattern.compile("\\.com"); // 使用正则表达式
        Matcher matcher = pattern.matcher(url); // 创建匹配器
        boolean matches = matcher.find(); // 查找匹配
        System.out.println("Matches .com? " + matches);
    }
}

性能对比

我们可以通过测量两种方法的执行时间来评估性能。使用 System.currentTimeMillis() 进行简单的时间测量:

java 复制代码
public class PerformanceTest {
    public static void testContains() {
        String url = "https://www.example.com";
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++) {
            url.contains(".com");
        }
        long endTime = System.currentTimeMillis();
        System.out.println("Contains took " + (endTime - startTime) + " ms");
    }

    public static void testRegex() {
        String url = "https://www.example.com";
        Pattern pattern = Pattern.compile("\\.com");
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++) {
            Matcher matcher = pattern.matcher(url);
            matcher.find();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("Regex took " + (endTime - startTime) + " ms");
    }

    public static void main(String[] args) {
        testContains();
        testRegex();
    }
}

运行结果可能会显示 String.contains() 方法快于正则表达式。但在某些情况下,正则表达式可以提供更灵活的匹配方案,例如匹配多个模式。

实验 2:复杂的模式匹配

假设你需要验证一个字符串是否符合某种复杂的模式,比如一个有效的电子邮件地址。你会如何处理?

方案 1:使用多个条件判断

java 复制代码
public class TestEmail1 {
    public static boolean isValidEmail(String email) {
        if (email == null || email.isEmpty()) {
            return false;
        }
        if (!email.contains("@")) {
            return false;
        }
        if (email.indexOf('@') == 0 || email.lastIndexOf('@') == email.length() - 1) {
            return false;
        }
        if (!email.contains(".")) {
            return false;
        }
        if (email.indexOf('.') == 0 || email.lastIndexOf('.') == email.length() - 1) {
            return false;
        }
        if (email.lastIndexOf('.') < email.lastIndexOf('@')) {
            return false;
        }
        return true;
    }

    public static void main(String[] args) {
        String email = "test@example.com";
        System.out.println("Is valid email? " + isValidEmail(email));
    }
}

方案 2:使用正则表达式

java 复制代码
import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class TestEmail2 {
    private static final Pattern EMAIL_PATTERN = Pattern.compile(
        "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$" // 复杂的正则表达式
    );

    public static boolean isValidEmail(String email) {
        if (email == null) {
            return false;
        }
        Matcher matcher = EMAIL_PATTERN.matcher(email);
        return matcher.matches(); // 正则表达式匹配
    }

    public static void main(String[] args) {
        String email = "test@example.com";
        System.out.println("Is valid email? " + isValidEmail(email));
    }
}

性能对比

同样是通过测量执行时间来评估性能:

java 复制代码
public class EmailValidationPerformanceTest {
    public static void testEmail1() {
        String email = "test@example.com";
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++) {
            TestEmail1.isValidEmail(email);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("Multiple conditions took " + (endTime - startTime) + " ms");
    }

    public static void testEmail2() {
        String email = "test@example.com";
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++) {
            TestEmail2.isValidEmail(email);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("Regex took " + (endTime - startTime) + " ms");
    }

    public static void main(String[] args) {
        testEmail1();
        testEmail2();
    }
}

运行结果可能会显示正则表达式的性能略逊一筹,但它的代码简洁性和可维护性远超多个条件判断的方法。

实验 3:替换操作

假设你需要将一个字符串中的所有空格替换为下划线。你会如何实现?

方案 1:使用 String.replaceAll() 方法

java 复制代码
public class TestReplaceAll {
    public static void main(String[] args) {
        String input = "Hello World This Is Java";
        String output = input.replaceAll(" ", "_"); // 使用正则表达式替换空格
        System.out.println("Output: " + output);
    }
}

方案 2:使用 StringBuilder 手动替换

java 复制代码
public class TestStringBuilder {
    public static String replaceSpaces(String input) {
        StringBuilder sb = new StringBuilder();
        for (char c : input.toCharArray()) {
            if (c == ' ') {
                sb.append('_'); // 手动替换空格
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    public static void main(String[] args) {
        String input = "Hello World This Is Java";
        String output = replaceSpaces(input);
        System.out.println("Output: " + output);
    }
}

性能对比

再次通过测量执行时间来评估性能:

java 复制代码
public class ReplacePerformanceTest {
    public static void testReplaceAll() {
        String input = "Hello World This Is Java";
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++) {
            input.replaceAll(" ", "_");
        }
        long endTime = System.currentTimeMillis();
        System.out.println("ReplaceAll took " + (endTime - startTime) + " ms");
    }

    public static void testStringBuilder() {
        String input = "Hello World This Is Java";
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++) {
            TestStringBuilder.replaceSpaces(input);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("StringBuilder took " + (endTime - startTime) + " ms");
    }

    public static void main(String[] args) {
        testReplaceAll();
        testStringBuilder();
    }
}

结果可能会显示 StringBuilder 方法更快,但在简单的替换操作中,使用正则表达式可以大大简化代码。

实验 4:分组捕获

假设你需要从一个字符串中提取特定的部分,比如从一个 URL 中提取主机名和路径。你会如何处理?

方案 1:手动解析

java 复制代码
public class TestManualParsing {
    public static String[] extractParts(String url) {
        int start = url.indexOf("://") + 3;
        int end = url.indexOf('/', start);
        String host = url.substring(start, end); // 提取主机名
        String path = url.substring(end); // 提取路径
        return new String[]{host, path};
    }

    public static void main(String[] args) {
        String url = "https://www.example.com/path/to/resource";
        String[] parts = extractParts(url);
        System.out.println("Host: " + parts[0]);
        System.out.println("Path: " + parts[1]);
    }
}

方案 2:使用正则表达式分组捕获

java 复制代码
import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class TestRegexGroup {
    private static final Pattern URL_PATTERN = Pattern.compile(
        "https?://(.*?)/(.*)" // 使用分组捕获
    );

    public static String[] extractParts(String url) {
        Matcher matcher = URL_PATTERN.matcher(url);
        if (matcher.matches()) {
            String host = matcher.group(1); // 提取主机名
            String path = matcher.group(2); // 提取路径
            return new String[]{host, path};
        }
        return null;
    }

    public static void main(String[] args) {
        String url = "https://www.example.com/path/to/resource";
        String[] parts = extractParts(url);
        System.out.println("Host: " + parts[0]);
        System.out.println("Path: " + parts[1]);
    }
}

性能对比

同样的,通过测量执行时间来评估性能:

java 复制代码
public class GroupCapturePerformanceTest {
    public static void testManualParsing() {
        String url = "https://www.example.com/path/to/resource";
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++) {
            TestManualParsing.extractParts(url);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("Manual parsing took " + (endTime - startTime) + " ms");
    }

    public static void testRegexGroup() {
        String url = "https://www.example.com/path/to/resource";
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++) {
            TestRegexGroup.extractParts(url);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("Regex group took " + (endTime - startTime) + " ms");
    }

    public static void main(String[] args) {
        testManualParsing();
        testRegexGroup();
    }
}

结果可能会显示手动解析更快,但在处理复杂的字符串时,正则表达式的分组捕获功能可以显著减少代码量和复杂性。

实验 5:编译优化

Java 正则表达式的一个重要特性是可以编译正则表达式以提高性能。让我们看看编译前后的性能差异。

方案 1:未编译的正则表达式

java 复制代码
public class TestUncompiledRegex {
    public static void main(String[] args) {
        String input = "Hello World This Is Java";
        boolean matches = input.matches(".*\\s.*"); // 未编译的正则表达式
        System.out.println("Matches? " + matches);
    }
}

方案 2:编译后的正则表达式

java 复制代码
import java.util.regex.Pattern;

public class TestCompiledRegex {
    private static final Pattern SPACE_PATTERN = Pattern.compile(".*\\s.*"); // 编译后的正则表达式

    public static void main(String[] args) {
        String input = "Hello World This Is Java";
        boolean matches = SPACE_PATTERN.matcher(input).matches(); // 使用编译后的正则表达式
        System.out.println("Matches? " + matches);
    }
}

性能对比

通过测量执行时间来评估编译优化的效果:

java 复制代码
public class CompilationPerformanceTest {
    public static void testUncompiled() {
        String input = "Hello World This Is Java";
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++) {
            input.matches(".*\\s.*");
        }
        long endTime = System.currentTimeMillis();
        System.out.println("Uncompiled regex took " + (endTime - startTime) + " ms");
    }

    public static void testCompiled() {
        String input = "Hello World This Is Java";
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < 1000000; i++) {
            TestCompiledRegex.SPACE_PATTERN.matcher(input).matches();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("Compiled regex took " + (endTime - startTime) + " ms");
    }

    public static void main(String[] args) {
        testUncompiled();
        testCompiled();
    }
}

结果可能会显示编译后的正则表达式性能明显提升,特别是在多次使用同一正则表达式时。

写在最后

通过上述实验,我们可以看到 Java 正则表达式在不同场景下的表现和优势。虽然在某些简单的情况下,传统的字符串方法可能会更快,但在处理复杂的字符串匹配和替换时,正则表达式的简洁性和灵活性使其成为不可或缺的工具。

如果你对正则表达式的构建和测试有更多需求,不妨试试 Hey Cron。这个网站提供了多种实用的工具,包括正则表达式生成器,可以帮助你快速构建和测试正则表达式,提高开发效率。同时,Hey Cron 还支持 Cron 表达式生成器、中英互译、JSON 格式化、Base64 编码解码、时间戳转换和 JWT 解析等功能,是开发者日常工作中的一大助力。

相关推荐
Eiceblue14 分钟前
使用 Python 实现 Excel 行列转置(保留单元格样式)
前端·python·excel
西西学代码29 分钟前
像素和颜色之间的转换(Flutter)
前端·javascript·flutter
茶底世界之下42 分钟前
羽毛颜色已经很鲜艳,还要继续加色吗?用 Awaking 试一次减饱和
前端·ios·运营
风早爽太1 小时前
Mac 搭建 Vue 开发环境
前端·vue.js
Lank_M1 小时前
Word图片裁剪转HTML失效,转换器各漏读了哪一层
前端
青烟小生1 小时前
前端架构设计实战:从组件思维到系统思维
前端
Amos_Web1 小时前
Rspack 源码解析(二十):Typed Hook 系统如何靠宏生成
前端·rust·前端框架
程序员大阳1 小时前
副队长CSS教程(29)–CSS Grid 实战:实现通用图文混排布局
前端·css·grid·图文混排
对空六课2 小时前
无头浏览器访问对跳出率的过滤规则
服务器·前端·算法·数据分析
小番茄夫斯基2 小时前
Nginx 介绍
前端