Jartap Jartap
首页
  • 正则表达式
  • 字符匹配基础
  • 量词与重复匹配
  • 分组与引用
  • 各语言正则表达式用法概览

分组与捕获

正则表达式中的分组是将多个字符或子模式组合成一个单元的重要机制,它允许你对部分正则模式进行特殊处理。分组是正则表达式强大功能的核心之一。

分组通过圆括号 () 构造,主要作用包括:

  1. 将多个元素视为一个整体

    ab+ # 匹配ab一次或者多次,如:ab,abb,abbb
    (ab)+ # 匹配"ab"一次或者多次,如ab,abab,ababab
    
  2. 捕获匹配内容供后续使用

    把"Jartap,05/21 2025",转换为"Jartap,2025-05-21"格式。用正则表达式捕获 月、日、年 三个分组。使用 $1表示分组月、$2表示分组日、$3表示分组年 按分组顺序重新排列,变成 年-月-日 格式。确保 Jartap, 部分不受影响。关于引用的语法不通的引擎稍有不同,JavaScript、Java、sed 使用 $1, $2, $3 引用分组,Python、Perl、Vim、GNU grep 使用 \1, \2, \3 引用分组。

    const text = "Jartap,05/21 2025";
    const newText = text.replace(/(\d{2})\/(\d{2})\s(\d{4})/, '$3-$1-$2');
    console.log(newText); // 输出: Jartap,2025-05-21
    
    public class Main {
        public static void main(String[] args) {
            String text = "Jartap,05/21 2025";
            String newText = text.replaceAll("(\\d{2})/(\\d{2}) (\\d{4})", "$3-$1-$2"); //在字符串替换中使用$1,但是在正则表达式中还是使用\1
            System.out.println(newText); // 输出: "Jartap,2025-05-21"
        }
    }
    
    import re
    
    text = "Jartap,05/21 2025"
    new_text = re.sub(r'(\d{2})/(\d{2}) (\d{4})', r'\3-\1-\2', text)
    print(new_text)  # 输出: "Jartap,2025-05-21"
    
  3. 应用量词到整个子模式

  4. 创建可读性更好的复杂模式

下面介绍下分组类型

捕获分组

英文名称是Capturing Groups,语法是(pattern),特点是匹配并记住内容、自动分配编号(从左到右,从1开始)、可通过反向引用或程序提取

示例:

# 假设文本为"这是一段数字字符串123-4567一二三"  匹配"123-4567",分组1="123",分组2="4567"
(\d{3})-(\d{4})

非捕获分组

英文名称是Non-capturing Groups,如果某些分组仅用于逻辑匹配,但不需要后续引用,可以使用 (?:...) 减少内存占用, 其不占用引用分组序号。 如:

const date = "2023-05-21";

// 普通分组(捕获月份和日,但不需要)
const matchWithCapture = date.match(/(\d{4})-(\d{2})-(\d{2})/);
console.log(matchWithCapture[1]); // "2023"(但 `$2`, `$3` 也被存储)

// 非捕获分组(只关心年份)
const matchWithoutCapture = date.match(/(\d{4})-(?:\d{2})-(?:\d{2})/);
console.log(matchWithoutCapture[1]); // "05"(`$2`, `$3` 不存储)

命名捕获组

英文名称是Named Capturing Groups,命名分组允许我们给正则表达式中的捕获组分配一个名称,而不是仅通过 $1、$2 或 \1、\2 这样的数字索引来引用。这样可以提高代码的可读性和可维护性,特别是在复杂的正则表达式中。

const text = "2023-05-21";

// 使用命名分组匹配日期
const pattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = text.match(pattern);

console.log(match.groups.year);  // "2023"
console.log(match.groups.month); // "05"
console.log(match.groups.day);   // "21"

// 在替换中使用命名分组
const newText = text.replace(pattern, "$<day>/$<month>/$<year>");
console.log(newText); // "21/05/2023"

注释分组

注释分组(Comment Group) 是正则表达式中一种特殊的语法结构,用于在正则模式中嵌入解释性注释,而不会影响实际的匹配行为。它的主要作用是提高正则表达式的可读性,尤其是对于复杂模式。属于PCRE语法规则,其语法格式是:(?#...),支持的引擎有:Python,.NET7.0,PHP,grep -P;不支持的引擎有:Golang,Java, JavaScript,Rust

对于正则表达式(abc)(?#这是一个注释)123,

验证文本为abc123Jartap,其匹配结果为:匹配上abc123,分组1的内容为:abc

可以通过grep进行验证grep默认是BRE模式,使用-E开启ERE模式,使用-P开启PCRC模式

echo "t注释est" | grep  't(注释)est' #输出为空,没有任何匹配,
# 在BRE中( )是普通字符;定义子表达式(分组)需要使用\(\)形式,在ERE中使用()即可
echo "t注释est" | grep  't\(注释\)est' #输出为: t注释est
echo "test" | grep  't(?#注释)est' #输出为空,没有任何匹配
echo "test" | grep -E 't(?#注释)est' #输出为空,没有任何匹配
echo "t#注释est" | grep -E 't(?#注释)est' #输出为:t#注释est
echo "test" | grep -P 't(?#注释)est' #输出为:test