4. 通配符与模式匹配深入

在 Snakemake 中,通配符(wildcards)是把一条规则从“只能处理一个文件”变成“能处理任意样本”的核心机制。规则里的 {sample}、{batch} 这类占位符,会在运行时被目标文件名反向填充,从而让同一条规则被复用几十上百次。理解通配符的匹配逻辑,是写出可扩展组学流程的分水岭。

一、通配符的本质:从目标反推输入

Snakemake 不是按顺序执行规则,而是从最终目标文件出发,反向寻找能生成它的规则。假设目标为 results/align/S1.bam,规则写作:

rule align:
    input:  "data/trim/{sample}.fq.gz"
    output: "results/align/{sample}.bam"
    shell:  "bwa mem ref.fa {input} | samtools sort -o {output}"

Snakemake 用输出模式 results/align/{sample}.bam 去匹配目标路径,提取出 sample = S1,再把该值代入输入模式,得到 data/trim/S1.fq.gz。这就是“模式匹配 + 变量绑定”的完整过程。通配符的值不是预先声明的,而是由文件名结构决定的。

二、wildcards 约束:用正则收紧匹配范围

默认情况下,通配符匹配任意非空字符串,这很容易造成歧义。例如同时存在 {sample}.bam 和 {sample}.sorted.bam 两条规则时,S1.sorted.bam 可能被第一条规则误匹配,把 sample 解析成 S1.sorted。解决办法是给通配符加约束:

wildcard_constraints:
    sample = r"[A-Za-z0-9_]+"

约束可以写在全局,也可以写在单条规则内。约束本质是正则表达式,它限定了通配符能匹配的字符集合。常见写法包括:样本名限定为字母数字下划线 [A-Za-z0-9_]+;批次号限定为数字 \d+;染色体限定为 chr[0-9XY]+。约束越精确,歧义越少,报错也越早、越清晰。

当流程中出现“Multiple rules match”或“ambiguous rule”报错时,第一反应应是检查通配符约束是否过宽,而不是急着改文件名。

三、正则匹配与命名捕获

Snakemake 的通配符约束支持完整的 Python 正则语法,包括命名捕获组。当需要从文件名中同时提取多个字段时,可以用命名组让语义更明确:

wildcard_constraints:
    sample = r"(?P<tissue>[A-Za-z]+)_(?P<rep>\d+)"

这样 liver_1 会被解析为 tissue=liver、rep=1。命名捕获组在复杂命名规范(如 tissue_rep_batch)下尤其有用,它让通配符的语义从“一段字符串”升级为“有结构的字段”。需要注意的是,命名组一旦使用,规则内引用时仍用 {sample} 整体,而组内字段可通过 wildcards.tissue 在代码块中访问。

四、动态通配符与函数式输入

有些输入无法用固定模式表达,例如样本对应的测序读长文件数量不定,或需要根据样本名查表决定输入路径。这时可用输入函数:

def get_fastq(wildcards):
    return expand("data/{s}_R{r}.fq.gz", s=wildcards.sample, r=[1,2])

rule trim:
    input:  get_fastq
    output: "results/trim/{sample}.fq.gz"
    shell:  "fastp -i {input[0]} -I {input[1]} -o {output}"

输入函数在运行时才被调用,能访问 wildcards 对象,从而实现“动态通配符”——输入列表随样本变化。这是处理双端/单端混合、多样本合并、按配置表取路径等场景的标准手段。

五、多样本并行与歧义排查

多样本并行依赖 expand() 生成目标列表,再由 Snakemake 调度:

SAMPLES = ["S1", "S2", "S3"]
rule all:
    input: expand("results/align/{sample}.bam", sample=SAMPLES)

常见歧义有三类:一是模式重叠,如 {sample}.bam 与 {sample}.sorted.bam 同时存在;二是通配符过宽,把目录名也吞进样本名;三是 expand() 中变量名与规则内通配符名不一致,导致目标无法被任何规则生成。排查时可用 snakemake -n -r 查看规则匹配情况,或 snakemake --dry-run 观察每个目标由哪条规则生成。

通配符匹配与歧义排查路径 目标文件 results/align/S1.bam 输出模式匹配 results/align/{sample}.bam 提取通配符值 sample = "S1" wildcard_constraints sample = [A-Za-z0-9_]+ 代入输入模式 data/trim/S1.fq.gz 常见歧义与排查手段 模式重叠 {sample}.bam 与 {sample}.sorted.bam 通配符过宽 目录名被吞入样本名 变量名不一致 expand 名 ≠ 规则通配符名 排查命令: snakemake -n -r 查看规则匹配;snakemake --dry-run 观察每个目标由哪条规则生成

六、实践中的命名规范建议

通配符歧义往往源于命名不规范。建议在流程设计阶段就固定样本命名规则,例如 {tissue}_{rep},并让所有规则共享同一套 wildcard_constraints。把约束集中写在 Snakefile 顶部,既避免重复,也便于统一维护。当样本量从几个扩展到几百个时,这套约束就是流程稳定性的护栏。

最后要记住:通配符是“模式”,不是“变量声明”。它的值由文件名结构决定,约束由正则决定,动态性由输入函数提供。把这三者分清,多样本并行和歧义排查都会变得有章可循。