
本文介绍在 java 中使用正则表达式高效判断短字符串的字符能否按原始顺序(不要求连续)全部出现在长字符串中,并提供可直接运行的代码实现与关键注意事项。
本文介绍在 java 中使用正则表达式高效判断短字符串的字符能否按原始顺序(不要求连续)全部出现在长字符串中,并提供可直接运行的代码实现与关键注意事项。
要解决“判断字符串 A 的所有字符是否能在字符串 B 中以相同顺序(不强制相邻)依次出现”这一问题,本质是匹配一个子序列(subsequence),而非子串(substring)。Java 的 String.matches() 方法支持完整正则匹配(隐含 ^...$),因此我们只需构造一个能匹配“任意前缀 + A 的首字符 + 任意中间 + A 的次字符 + ... + 任意后缀”的正则模式。
核心思路非常简洁:将短字符串 word1 的每个字符 c 拆开,并在每两个字符之间插入 .*(匹配零个或多个任意字符),首尾再分别允许任意前导和尾随内容。例如:
- 输入 phantom → 正则为 ^.*p.*h.*a.*n.*t.*o.*m.*$
- 该模式能成功匹配 "p***ph***vnb***a***jknzxcvb***n***a***to***popoi***m***",因为 .* 充分覆盖了字符间的干扰内容。
以下是优化后的完整实现(已修复原代码中的关键错误):
import java.util.Scanner;
import java.util.stream.Collectors;
public class SubsequenceRegex {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String word1 = input.next().trim();
String word2 = input.next().trim();
// 构造正则:每个字符前加 ".*",最后补一个 ".*",并锚定首尾
String pattern = "^" + word1.chars()
.mapToObj(c -> ".*" + Pattern.quote((char) c))
.collect(Collectors.joining()) + ".*$";
System.out.println(word2.matches(pattern));
}
}⚠️ 关键注意事项:
- [:alnum:] 不是 Java 正则的有效字符类(它是 POSIX 扩展,在 Java Pattern 中不被识别);应使用 .* 表达“任意长度任意字符”。
- 必须对 word1 中的特殊正则字符(如 ., *, +, ?, $, ^, [, ], (, ), {, }, |, \)进行转义,否则会导致意外匹配失败。上面代码中使用 Pattern.quote((char) c) 安全处理此问题。
- .* 是贪婪匹配,但在此场景下完全适用——只要存在一种合法路径即可满足 matches() 的全串匹配要求。
- 时间复杂度取决于正则引擎优化,对于常规输入(长度 ≤ 数千)性能良好;极端超长字符串建议改用双指针 O(n+m) 算法(但本题明确要求 Regex 解法)。
总结:该方案以最小正则开销精准建模子序列语义,代码简洁、逻辑清晰、鲁棒性强,是 Java 中实现“有序字符存在性检测”的标准正则解法。










