Java 字符串查找

一、方法 1:indexOf ()/lastIndexOf ()(基础位置查找)

indexOf() 是 Java 字符串最基础的查找方法,用于定位字符 / 子串首次出现的索引lastIndexOf() 则定位最后一次出现的索引,两者是处理简单查找需求的首选。

核心语法

// 查找字符首次出现的索引
int indexOf(int ch);
// 从指定位置开始查找字符
int indexOf(int ch, int fromIndex);
// 查找子串首次出现的索引
int indexOf(String str);
// 从指定位置开始查找子串
int indexOf(String str, int fromIndex);

// lastIndexOf() 语法与indexOf()一致,仅查找方向相反(从末尾往前)
 

完整代码示例 

public class StringSearchDemo {
    public static void main(String[] args) {
        String original = "Java is a programming language, Java is easy to learn";
        // 空值校验(实际开发必备)
        if (original == null) {
            System.out.println("字符串不能为空");
            return;
        }

        // 1. 查找字符首次出现的索引(字符'a'的ASCII码是97,也可直接传'a')
        int charFirstIndex = original.indexOf('a');
        System.out.println("字符'a'首次出现的索引:" + charFirstIndex); // 输出:1

        // 2. 查找子串首次出现的索引
        int strFirstIndex = original.indexOf("Java");
        System.out.println("子串'Java'首次出现的索引:" + strFirstIndex); // 输出:0

        // 3. 从指定位置(索引10)开始查找子串
        int strFromIndex = original.indexOf("Java", 10);
        System.out.println("从索引10开始查找'Java'的索引:" + strFromIndex); // 输出:32

        // 4. 查找子串最后一次出现的索引
        int strLastIndex = original.lastIndexOf("Java");
        System.out.println("子串'Java'最后一次出现的索引:" + strLastIndex); // 输出:32

        // 5. 查找不存在的子串(返回-1,核心判断依据)
        int notExistIndex = original.indexOf("Python");
        System.out.println("不存在的子串返回值:" + notExistIndex); // 输出:-1
    }
}
 

关键说明

  • 返回值规则:找到则返回索引(从 0 开始),未找到返回-1(这是判断是否存在的核心依据);
  • 性能特点:时间复杂度O(n)(n 为字符串长度),底层基于字符数组遍历,效率极高;
  • 适用场景:简单的字符 / 子串位置查找(如判断关键词是否存在、提取指定位置前的文本)。

二、方法 2:contains ()(存在性判断)

若仅需判断子串是否存在,无需获取具体索引,优先使用contains(),代码更简洁、语义更清晰。

核心语法

boolean contains(CharSequence s);
 

完整代码示例

public class StringSearchDemo {
    public static void main(String[] args) {
        String original = "Hello Java, Hello World";
        
        // 判断子串是否存在
        boolean hasJava = original.contains("Java");
        boolean hasPython = original.contains("Python");
        
        System.out.println("是否包含'Java':" + hasJava); // 输出:true
        System.out.println("是否包含'Python':" + hasPython); // 输出:false
    }
}
 

关键说明

  • 底层逻辑contains() 本质是调用 indexOf(s) != -1,性能与indexOf()一致;
  • 适用场景:仅需判断 “有 / 无” 的场景(如表单关键词过滤、文本内容校验);
  • 注意点:参数是CharSequence类型,可直接传入 String、StringBuilder 等,无需类型转换。

三、方法 3:matches ()(正则表达式匹配)

当查找需求涉及复杂规则(如手机号、邮箱、模糊匹配),需使用matches()结合正则表达式,实现灵活的模式查找。

核心语法 

boolean matches(String regex);
 

完整代码示例 

public class StringSearchDemo {
    public static void main(String[] args) {
        // 1. 匹配邮箱格式
        String email = "test@example.com";
        String emailRegex = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$";
        boolean isEmail = email.matches(emailRegex);
        System.out.println("是否为合法邮箱:" + isEmail); // 输出:true

        // 2. 匹配手机号(11位,以1开头)
        String phone = "13812345678";
        String phoneRegex = "^1[3-9]\\d{9}$";
        boolean isPhone = phone.matches(phoneRegex);
        System.out.println("是否为合法手机号:" + isPhone); // 输出:true

        // 3. 模糊匹配(包含任意数字)
        String text = "Java8 is better than Java7";
        String numRegex = ".*\\d+.*"; // .*表示任意字符,\\d+表示至少一个数字
        boolean hasNum = text.matches(numRegex);
        System.out.println("是否包含数字:" + hasNum); // 输出:true
    }
}
 

关键说明

  • 底层逻辑:基于正则表达式引擎匹配,功能强大但性能低于indexOf()/contains()
  • 适用场景:复杂规则匹配(如格式校验、模糊查找、特殊字符过滤);
  • 注意点matches() 会匹配整个字符串(而非子串),若需匹配子串,需在正则前后加.*

四、方法 4:Pattern + Matcher(高效正则查找)

matches() 每次调用都会重新编译正则表达式,若需高频次匹配同一规则(如批量校验 10 万条手机号),需使用Pattern预编译正则,结合Matcher实现高效查找。

完整代码示例 

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class StringSearchDemo {
    public static void main(String[] args) {
        // 预编译正则表达式(仅编译一次,复用多次)
        Pattern phonePattern = Pattern.compile("^1[3-9]\\d{9}$");

        // 批量校验手机号
        String[] phones = {"13812345678", "12345678901", "19987654321"};
        for (String phone : phones) {
            Matcher matcher = phonePattern.matcher(phone);
            boolean isPhone = matcher.matches();
            System.out.println(phone + " 是否为合法手机号:" + isPhone);
        }

        // 查找字符串中所有数字子串
        String text = "Java8 发布于2014年,Java17 发布于2021年";
        Pattern numPattern = Pattern.compile("\\d+"); // 匹配数字子串
        Matcher numMatcher = numPattern.matcher(text);
        
        System.out.println("\n提取的数字子串:");
        while (numMatcher.find()) { // 遍历所有匹配的子串
            String num = numMatcher.group(); // 获取匹配的内容
            int start = numMatcher.start(); // 获取匹配的起始索引
            int end = numMatcher.end(); // 获取匹配的结束索引
            System.out.println("内容:" + num + ",起始索引:" + start + ",结束索引:" + end);
        }
    }
}
 

输出结果

13812345678 是否为合法手机号:true
12345678901 是否为合法手机号:false
19987654321 是否为合法手机号:true

提取的数字子串:
内容:8,起始索引:4,结束索引:5
内容:2014,起始索引:9,结束索引:13
内容:17,起始索引:18,结束索引:20
内容:2021,起始索引:24,结束索引:28
 

关键说明

  • 核心优势Pattern预编译后可复用,避免重复编译正则的性能损耗,高频场景下效率提升 10 倍以上;
  • 核心方法
    • matcher.find():查找下一个匹配的子串;
    • matcher.group():获取当前匹配的内容;
    • matcher.start()/end():获取匹配内容的起止索引;
  • 适用场景:批量数据校验、提取字符串中所有符合规则的子串。

五、方法 5:String.indexOf () 循环查找(批量子串查找)

若需查找字符串中所有目标子串的位置(如统计关键词出现次数),可通过indexOf()循环实现,相比正则更高效。

完整代码示例 

public class StringSearchDemo {
    public static void main(String[] args) {
        String original = "Java is Java, Java is everywhere";
        String target = "Java";
        int count = 0; // 统计出现次数
        int index = 0; // 起始查找位置

        // 循环查找所有目标子串
        while ((index = original.indexOf(target, index)) != -1) {
            count++;
            System.out.println("找到'" + target + "',索引:" + index);
            index += target.length(); // 移动查找位置,避免重复匹配
        }

        System.out.println("'" + target + "' 总共出现:" + count + " 次");
    }
}
 

输出结果

找到'Java',索引:0
找到'Java',索引:8
找到'Java',索引:14
'Java' 总共出现:3 次
 

关键说明

  • 核心逻辑:每次找到子串后,将查找起始位置移至当前索引 + 子串长度,避免重复匹配(如 “JavaJava” 中只匹配两次);
  • 性能特点:纯字符数组遍历,效率远高于正则,适合长文本、高频次的批量查找;
  • 适用场景:统计关键词出现次数、提取所有关键词的位置。

六、实战对比与避坑指南

1. 方法选型对比

方法优点缺点适用场景
indexOf()/lastIndexOf() 高效、简单 仅支持简单查找 单个字符 / 子串位置查找
contains() 语义清晰、代码简洁 仅判断存在性 子串存在性校验
matches() 支持复杂正则 性能低、每次编译正则 单次简单正则匹配
Pattern + Matcher 高效、支持复杂规则 代码稍复杂 批量正则匹配、提取子串
indexOf () 循环 高效、可控性强 需手动处理循环 批量子串查找、次数统计

2. 常见避坑点

  • 空指针异常:查找前必须校验字符串是否为null,否则调用indexOf()/contains()会抛出NullPointerException
  • 正则转义:正则中的特殊字符(如.*+)需转义(加\\),否则匹配结果错误;
  • 重复匹配:循环查找时需移动起始位置,避免同一子串被多次匹配;
  • 全字符串匹配matches() 匹配整个字符串,若需匹配子串,正则前后需加.*(如".*Java.*"

posted on 2025-12-22 13:38  coding博客  阅读(1)  评论(0)    收藏  举报