一文秒懂Java正则表达式中 `\\1` 和 `$1` 的使用场景

Java正则表达式中 \\1$1 的使用场景

1. 根本区别

语法使用场景作用示例
\\1正则表达式模式反向引用已匹配的捕获组"(a)\\1" 匹配 “aa”
$1替换字符串引用匹配到的捕获组replaceAll("(a)", "$1$1")

2. \\1 - 正则表达式模式中的反向引用

基本用法

public class BackreferenceInPattern {
    public static void main(String[] args) {
        String[] testCases = {
            "abab",     // 匹配 - 重复 "ab"
            "abcd",     // 不匹配
            "1111",     // 匹配 - 重复 "11"
            "aabb",     // 匹配 - 重复 "aa" 和 "bb"
        };
        
        // \\1 引用第一个捕获组匹配的内容
        String regex = "(\\w{2})\\1";  // 匹配重复的两位字符
        
        Pattern pattern = Pattern.compile(regex);
        
        for (String test : testCases) {
            Matcher matcher = pattern.matcher(test);
            //格式化参数
            System.out.printf("'%s' %s匹配模式 %s%n", 
            	test, 
                matcher.find() ? "【ok】" : "【no】", 
                regex);
        }
    }
}

输出:

'abab' 【ok】匹配模式 (\w{2})\1
'abcd' 【no】匹配模式 (\w{2})\1
'1111' 【ok】匹配模式 (\w{2})\1
'aabb' 【ok】匹配模式 (\w{2})\1

复杂反向引用示例

public class ComplexBackreference {
    public static void main(String[] args) {
        // 匹配重复的单词
        String text = "hello hello world world java java programming";
        String regex = "\\b(\\w+)\\s+\\1\\b";  // \\1 引用前面匹配的单词
        
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(text);
        
        System.out.println("找到的重复单词:");
        while (matcher.find()) {
            System.out.println("'" + matcher.group(1) + "' 重复出现在: '" + matcher.group() + "'");
        }
        
        // 匹配HTML标签对
        String html = "<div>content</div> <p>text</p> <span>hello</span>";
        String tagRegex = "<(\\w+)>[^<]+</\\1>";  // \\1 确保开始和结束标签相同
        
        System.out.println("\n匹配的HTML标签对:");
        Pattern tagPattern = Pattern.compile(tagRegex);
        Matcher tagMatcher = tagPattern.matcher(html);
        
        while (tagMatcher.find()) {
            System.out.println("标签: " + tagMatcher.group(1) + ", 内容: " + tagMatcher.group());
        }
    }
}

3. $1 - 替换字符串中的引用

基本用法

public class DollarInReplacement {
    public static void main(String[] args) {
        String input = "John Smith (25) from New York";
        
        // 重新排列信息
        String rearranged = input.replaceAll("(\\w+)\\s+(\\w+)\\s+\\((\\d+)\\)\\s+from\\s+(.+)", 
                                           "$2, $1 (Age: $3) - $4");
        System.out.println("重新排列: " + rearranged);
        
        // 格式化电话号码
        String phone = "13800138000";
        String formattedPhone = phone.replaceAll("(\\d{3})(\\d{4})(\\d{4})", "$1-$2-$3");
        System.out.println("格式化电话: " + formattedPhone);
        
        // 日期格式转换
        String date = "2023-12-25";
        String usDate = date.replaceAll("(\\d{4})-(\\d{2})-(\\d{2})", "$2/$3/$1");
        //如果是中式日期,直接用/替换,可如果我是美式日期呢,这个使用场景不就体现了吗
        System.out.println("美式日期: " + usDate);
    }
}

appendReplacement 中使用 $1

public class DollarInAppendReplacement {
    public static void main(String[] args) {
        String text = "价格: $25.99, 重量: 2.5kg, 数量: 10个";
        String regex = "([$¥]?)(\\d+(?:\\.\\d+)?)([a-zA-Z个件]*)\\b";
        
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(text);
        StringBuffer result = new StringBuffer();
        
        while (matcher.find()) {
            // 使用 $1, $2, $3 引用捕获组
            String replacement;
            if ("$".equals(matcher.group(1))) {
                replacement = "[美元: " + matcher.group(2) + "]";
            } else if ("¥".equals(matcher.group(1))) {
                replacement = "[人民币: " + matcher.group(2) + "]";
            } else {
                replacement = "[数值: " + matcher.group(2) + matcher.group(3) + "]";
            }
            
            matcher.appendReplacement(result, replacement);
        }
        matcher.appendTail(result);
        
        System.out.println("原始: " + text);
        System.out.println("替换后: " + result.toString());
    }
}

4. 对比示例:相同需求的不同实现

public class CompareBackreferenceAndReplacement {
    public static void main(String[] args) {
        String input = "abc123def456";
        
        System.out.println("=== 场景1: 查找重复字符 ===");
        // 使用 \\1 在模式中查找重复
        findRepeatedCharacters(input);
        
        System.out.println("\n=== 场景2: 复制匹配内容 ===");
        // 使用 $1 在替换中复制内容
        duplicateMatchedContent(input);
        
        System.out.println("\n=== 场景3: 交换内容 ===");
        // 使用 $1, $2 等交换内容
        swapContent("firstName lastName");
    }
    
    static void findRepeatedCharacters(String input) {
        // 使用 \\1 在正则表达式模式中
        String regex = "(\\w)\\1";  // 查找连续重复的字符
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);
        
        System.out.println("在 '" + input + "' 中查找重复字符:");
        while (matcher.find()) {
            System.out.println("找到重复字符 '" + matcher.group(1) + "' 在: " + matcher.group());
        }
    }
    
    static void duplicateMatchedContent(String input) {
        // 使用 $1 在替换字符串中
        String duplicated = input.replaceAll("(\\d+)", "$1$1");  // 复制数字
        System.out.println("复制数字后: " + duplicated);
        
        String emphasized = input.replaceAll("(\\w+)", "**$1**");  // 强调所有单词
        System.out.println("强调单词: " + emphasized);
    }
    
    static void swapContent(String input) {
        // 使用 $1, $2 交换姓名顺序
        String swapped = input.replaceAll("(\\w+)\\s+(\\w+)", "$2, $1");
        System.out.println("姓名交换: '" + input + "' → '" + swapped + "'");
        
        // 更复杂的重组
        String complex = "2023年12月25日";
        String reformed = complex.replaceAll("(\\d+)年(\\d+)月(\\d+)日", "$1-$2-$3");
        System.out.println("日期重组: '" + complex + "' → '" + reformed + "'");
    }
}

5. 高级用法:嵌套和多重引用

public class AdvancedReferences {
    public static void main(String[] args) {
        // 多重反向引用
        String text = "abcabc123123xyzxyz";
        String regex = "(\\w+)(\\d+)\\1\\2";  // \\1 引用单词, \\2 引用数字
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(text);
        
        System.out.println("多重反向引用匹配:");
        while (matcher.find()) {
            System.out.println("完整匹配: " + matcher.group());
            System.out.println("单词部分: " + matcher.group(1));
            System.out.println("数字部分: " + matcher.group(2));
        }
        
        // 复杂替换
        String data = "name=John,age=25,city=New York";
        String sql = data.replaceAll("(\\w+)=([^,]+)", "$1='$2'");
        System.out.println("\nSQL格式: " + sql);
        
        // 使用 appendReplacement 的复杂替换
        StringBuffer buffer = new StringBuffer();
        Matcher m = Pattern.compile("(\\w+)=([^,]+)").matcher(data);
        while (m.find()) {
            String key = m.group(1);
            String value = m.group(2);
            // 根据不同的键进行不同的替换
            String replacement = switch (key) {
                case "name" -> "姓名: " + value;
                case "age" -> "年龄: " + value;
                case "city" -> "城市: " + value;
                default -> key + ": " + value;
            };
            m.appendReplacement(buffer, replacement);
        }
        m.appendTail(buffer);
        System.out.println("格式化数据: " + buffer.toString());
    }
}

6. 常见错误和注意事项

public class CommonMistakes {
    public static void main(String[] args) {
        String input = "hello world";
        
        // 错误1: 在模式中使用 $1
        try {
            String wrongRegex = "(\\w+) $1";  // 错误! 应该在模式中使用 \\1
            Pattern.compile(wrongRegex);
        } catch (Exception e) {
            System.out.println("错误1: " + e.getMessage());
        }
        
        // 错误2: 在替换中使用 \\1
        String wrongReplacement = input.replaceAll("(\\w+)", "\\\\1");  // 错误! 应该使用 $1
        System.out.println("错误替换结果: " + wrongReplacement);
        
        // 正确用法
        String correct1 = input.replaceAll("(\\w+) \\1", "REPEATED");  // 模式中用 \\1
        String correct2 = input.replaceAll("(\\w+)", "$1$1");          // 替换中用 $1
        
        System.out.println("正确结果1: " + correct1);
        System.out.println("正确结果2: " + correct2);
        
        // 转义注意事项
        System.out.println("\n=== 转义示例 ===");
        String withDollar = "价格: $100";
        // 要在替换中得到字面 $,需要转义
        String escaped = withDollar.replaceAll("\\$(\\d+)", "\\\\$$1");  // 得到: 价格: \$100
        System.out.println("转义结果: " + escaped);
    }
}

关键总结

\\1 的使用场景

  • 正则表达式模式
  • 用于匹配时引用前面已匹配的捕获组
  • 示例:"(ab)\\1" 匹配 “abab”

$1 的使用场景

  • 替换字符串
  • 用于替换时引用匹配到的捕获组
  • 示例:replaceAll("(a)", "$1$1") 把 “a” 替换为 “aa”

简单记忆

  • 模式中\\1, \\2, \\3…(双反斜杠)
  • 替换中$1, $2, $3…(美元符号)
  • 两者编号都从 1 开始,\\0$0 表示整个匹配
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值