杰瑞科技汇

Java中如何用正则表达式解析JSON?

  1. Java 中处理 JSON 的主流库
  2. Java 中的正则表达式基础
  3. 核心部分:JSON 与正则表达式的结合使用
  4. 一个完整的综合示例
  5. 最佳实践与注意事项

Java 中处理 JSON 的主流库

在 Java 中,没有内置的、原生的 JSON 库,最常用的是第三方库。

Java中如何用正则表达式解析JSON?-图1
(图片来源网络,侵删)

a) Jackson (推荐)

功能最强大、性能最好、社区最活跃的库,是 Spring Boot 等框架的默认选择。

  • 核心模块:

    • jackson-databind: 核心库,用于在 JSON 和 Java 对象之间进行绑定。
    • jackson-core: 底层 JSON 处理引擎。
    • jackson-annotations: 提供注解,方便地控制序列化和反序列化行为。
  • Maven 依赖:

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.15.2</version> <!-- 请使用最新版本 -->
    </dependency>

b) Gson

由 Google 开发,API 简单易用,非常适合小型项目或不需要复杂配置的场景。

Java中如何用正则表达式解析JSON?-图2
(图片来源网络,侵删)
  • Maven 依赖:
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.10.1</version> <!-- 请使用最新版本 -->
    </dependency>

c) org.json

一个轻量级的库,API 比较底层,需要手动操作 JSONObjectJSONArray

  • Maven 依赖:
    <dependency>
        <groupId>org.json</groupId>
        <artifactId>json</artifactId>
        <version>20251013</version> <!-- 请使用最新版本 -->
    </dependency>

Java 中的正则表达式基础

Java 通过 java.util.regex 包提供对正则表达式的支持。

核心类

  • Pattern: 正则表达式的编译表示,使用 Pattern.compile(regex) 方法创建。
  • Matcher: 对输入字符串进行解释和匹配的引擎,由 pattern.matcher(input) 方法创建。
  • PatternSyntaxException: 表示正则表达式模式中的语法错误。

常用方法示例

import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class RegexExample {
    public static void main(String[] args) {
        String text = "Hello my email is test.user-123@example.com and my phone is 123-456-7890.";
        String emailRegex = "\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b";
        String phoneRegex = "\\d{3}-\\d{3}-\\d{4}";
        // 1. 编译正则表达式
        Pattern emailPattern = Pattern.compile(emailRegex);
        Pattern phonePattern = Pattern.compile(phoneRegex);
        // 2. 创建匹配器
        Matcher emailMatcher = emailPattern.matcher(text);
        Matcher phoneMatcher = phonePattern.matcher(text);
        // 3. 查找并打印所有匹配项
        System.out.println("Found emails:");
        while (emailMatcher.find()) {
            // group() 返回匹配到的子序列
            System.out.println("- " + emailMatcher.group());
        }
        System.out.println("\nFound phones:");
        if (phoneMatcher.find()) {
            System.out.println("- " + phoneMatcher.group());
        }
    }
}

核心部分:JSON 与正则表达式的结合使用

这是最关键的部分,我们有两种需求场景:

在 JSON 字符串上直接使用正则表达式

当你有一个完整的 JSON 字符串,并且想从中提取符合特定模式的信息时(从日志文件中提取所有 JSON 对象中的特定字段)。

Java中如何用正则表达式解析JSON?-图3
(图片来源网络,侵删)

方法:

  1. 将整个 JSON 字符串视为一个普通的 String
  2. 编写一个正则表达式来匹配你想要的部分。
  3. 使用 PatternMatcher 进行查找。

示例: 从 JSON 字符串中提取所有 email 字段的值。

import java.util.regex.*;
public class RegexOnJsonString {
    public static void main(String[] args) {
        // 这是一个包含数组的 JSON 字符串
        String jsonString = "{\"users\": [" +
                "{\"id\": 1, \"name\": \"Alice\", \"email\": \"alice@example.com\"}," +
                "{\"id\": 2, \"name\": \"Bob\", \"email\": \"bob.test@sub-domain.org\"}," +
                "{\"id\": 3, \"name\": \"Charlie\", \"email\": \"charlie@example.co.uk\"}" +
                "]}";
        // 正则表达式解释:
        // "email":\s* - 匹配 "email": 后面可能有空格
        // " - 匹配开始的引号
        // ([^"]+) - 这是一个捕获组,匹配一个或多个非引号字符,这就是我们要的邮箱
        // " - 匹配结束的引号
        String emailRegex = "\"email\":\\s*\"([^\"]+)\"";
        Pattern pattern = Pattern.compile(emailRegex);
        Matcher matcher = pattern.matcher(jsonString);
        System.out.println("Extracted emails using regex on raw string:");
        while (matcher.find()) {
            // group(0) 是整个匹配项 ("email": "...")
            // group(1) 是第一个捕获组 (邮箱地址)
            System.out.println(matcher.group(1));
        }
    }
}

注意: 这种方法脆弱,JSON 结构稍有变化(比如字段顺序、空格变化),正则表达式就可能失效。不推荐用于解析复杂的 JSON,仅适用于简单的、格式固定的文本模式提取。

解析 JSON 后,在数据上使用正则表达式(推荐)

这是更健壮、更推荐的做法,先将 JSON 字符串解析成 Java 对象(如 List<Map>, 自定义 POJO, JSONArray 等),然后在结构化的数据上进行操作。

步骤:

  1. 使用 Jackson/Gson 等库将 JSON 字符串解析成 Java 对象。
  2. 遍历这个 Java 对象。
  3. 对每个需要验证的字符串字段,使用正则表达式进行匹配。

示例: 使用 Jackson 验证用户列表中的邮箱和手机号格式。

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
public class RegexAfterJsonParsing {
    public static void main(String[] args) throws Exception {
        String jsonString = "{\"users\": [" +
                "{\"id\": 1, \"name\": \"Alice\", \"email\": \"alice@example.com\", \"phone\": \"111-222-3333\"}," +
                "{\"id\": 2, \"name\": \"Bob\", \"email\": \"invalid-email\", \"phone\": \"444-555-6666\"}," +
                "{\"id\": 3, \"name\": \"Charlie\", \"email\": \"charlie@example.co.uk\", \"phone\": \"1234567890\"}" +
                "]}";
        // 1. 使用 Jackson 解析 JSON
        ObjectMapper mapper = new ObjectMapper();
        // TypeReference 可以帮助我们处理复杂的泛型类型,如 List<Map>
        List<Map<String, Object>> userList = mapper.readValue(jsonString, new TypeReference<List<Map<String, Object>>>() {});
        // 预编译正则表达式以提高性能
        Pattern emailPattern = Pattern.compile("^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}$");
        Pattern phonePattern = Pattern.compile("^\\d{3}-\\d{3}-\\d{4}$");
        System.out.println("Validating user data after parsing:");
        for (Map<String, Object> user : userList) {
            String name = (String) user.get("name");
            String email = (String) user.get("email");
            String phone = (String) user.get("phone");
            System.out.println("\nChecking user: " + name);
            System.out.println("  Email: " + email);
            System.out.println("  Phone: " + phone);
            // 2. 在解析后的数据上使用正则表达式
            if (email != null && !emailPattern.matcher(email).matches()) {
                System.out.println("  -> [ERROR] Invalid email format!");
            }
            if (phone != null && !phonePattern.matcher(phone).matches()) {
                System.out.println("  -> [ERROR] Invalid phone format!");
            }
        }
    }
}

一个完整的综合示例

这个示例将展示一个更实际的应用:从 API 返回的 JSON 响应中,提取所有符合特定格式的日志 ID。

模拟的 JSON 响应:

{
  "status": "success",
  "data": {
    "logs": [
      { "id": "log-abc-123", "level": "INFO", "message": "User logged in." },
      { "id": "error-def-456", "level": "ERROR", "message": "Failed to connect." },
      { "id": "log-ghi-789", "level": "DEBUG", "message": "Processing request." },
      { "id": "alert-jkl-012", "level": "WARN", "message": "Low memory warning." }
    ]
  }
}

目标: 提取所有 id 字段中以 "log-" 开头,并且后面跟着三个字母和三个数字的 ID。

代码实现:

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ComprehensiveExample {
    public static void main(String[] args) {
        String jsonResponse = "{\n" +
                "  \"status\": \"success\",\n" +
                "  \"data\": {\n" +
                "    \"logs\": [\n" +
                "      { \"id\": \"log-abc-123\", \"level\": \"INFO\", \"message\": \"User logged in.\" },\n" +
                "      { \"id\": \"error-def-456\", \"level\": \"ERROR\", \"message\": \"Failed to connect.\" },\n" +
                "      { \"id\": \"log-ghi-789\", \"level\": \"DEBUG\", \"message\": \"Processing request.\" },\n" +
                "      { \"id\": \"alert-jkl-012\", \"level\": \"WARN\", \"message\": \"Low memory warning.\" }\n" +
                "    ]\n" +
                "  }\n" +
                "}";
        // 1. 解析 JSON
        ObjectMapper mapper = new ObjectMapper();
        try {
            JsonNode rootNode = mapper.readTree(jsonResponse);
            JsonNode logsNode = rootNode.path("data").path("logs");
            // 2. 定义正则表达式
            // 解释: ^log- - 以 "log-" 开头
            // [a-zA-Z]{3} - 后面跟着3个字母
            // -\d{3}$ - 再跟着一个 "-" 和3个数字,直到字符串结束
            String logIdRegex = "^log-[a-zA-Z]{3}-\\d{3}$";
            Pattern pattern = Pattern.compile(logIdRegex);
            System.out.println("Extracting valid log IDs:");
            // 3. 遍历 JSON 数组
            for (JsonNode logNode : logsNode) {
                String id = logNode.path("id").asText();
                // 4. 对每个 ID 使用正则表达式进行匹配
                Matcher matcher = pattern.matcher(id);
                if (matcher.matches()) {
                    System.out.println(" - Found a valid log ID: " + id);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

输出:

Extracting valid log IDs:
 - Found a valid log ID: log-abc-123
 - Found a valid log ID: log-ghi-789

最佳实践与注意事项

  1. 优先选择 JSON 库: 永远不要用正则表达式来解析复杂的、结构不固定的 JSON,正则表达式是用于文本模式匹配的,而不是用于结构化数据解析的,使用 Jackson/Gson 等库是正确且健壮的做法。

  2. 预编译正则表达式: 如果你的正则表达式会被多次使用(例如在循环中),务必使用 Pattern.compile() 预编译它,而不是在每次循环中都调用 String.matches()Pattern.matches(),这样可以显著提高性能。

  3. 正则表达式性能: 复杂的正则表达式(如包含回溯的)可能会很慢,在处理大量数据时要注意性能问题,可以使用 Patterncompile 方法传入 Pattern.CASE_INSENSITIVE 等标志来优化。

  4. 可读性与维护性: 正则表达式很难读懂,为复杂的正则表达式添加注释,或者将其定义为常量,可以提高代码的可维护性。

    // 匹配标准的邮箱地址
    private static final String EMAIL_REGEX = "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}$";
    private static final Pattern EMAIL_PATTERN = Pattern.compile(EMAIL_REGEX);
  5. 转义: 在 Java 字符串中,反斜杠 \ 是一个转义字符,所以在写正则表达式时,你需要对它进行二次转义,匹配一个数字 \d 在 Java 字符串中要写成 "\\d"

希望这份详细的指南能帮助你掌握在 Java 中结合使用 JSON 和正则表达式!

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