와일드카드 제약 조건(Wildcard Constraints)으로 매칭 제한하기
와일드카드는 Snakemake의 가장 강력한 기능 중 하나입니다. 하지만 때로는 너무 광범위하게 매칭되어(예: 원치 않는 파일까지 매칭) 문제를 일으키기도 합니다.
와일드카드에 대한 기본 사항은 와일드카드 장을 참조하십시오.
기본적으로 Snakemake의 와일드카드는 하나 이상의 문자와 매칭됩니다. 즉, 빈 문자열과는 매칭되지 않지만 그 외의 거의 모든 것과 매칭됩니다. 이로 인해 앞서 논의한 것처럼 의도하지 않은 규칙 간 매칭이 발생할 수 있습니다.
Snakemake는 와일드카드 제약 조건(wildcard constraints)이라는 기능을 통해 매칭 범위를 제한하는 방법을 제공합니다. 와일드카드 제약 조건은 정규 표현식(regular expressions)을 사용하여 특정 와일드카드가 매칭할 수 있는 대상과 없는 대상을 유연하게 지정하는 시스템입니다.
정규 표현식(흔히 “regex” 또는 “regexp”라고 함)은 복잡한 문자열 매칭을 위해 설계된 미니 언어입니다.
몇 가지 유용한 예시: * \d+: 하나 이상의 숫자와 매칭 * [a-zA-Z]+: 하나 이상의 영문자와 매칭 * [^/]+: 슬래시(/)를 제외한 하나 이상의 문자와 매칭 (하위 디렉터리 매칭을 방지할 때 유용)
정규 표현식에 대한 자세한 내용은 Python 공식 문서의 Regular Expression HOWTO를 참조하는 것이 좋습니다.
glob_wildcards에서 와일드카드 제약 조건 사용하기
먼저 glob_wildcards에서 제약 조건을 어떻게 사용하는지 살펴보겠습니다. 다음 파일들이 들어 있는 디렉터리가 있다고 가정해 봅시다.
letters-only-abc-xyz.txt
letters-only-abc.txt
letters-only-abc2.txt
일반적인 방식으로 모든 파일을 매칭하면 다음과 같습니다.
files, = glob_wildcards('letters-only-{word}.txt')
# 결과: ['abc2', 'abc-xyz', 'abc']만약 숫자가 포함된 letters-only-abc2.txt를 제외하고 오직 문자만 있는 파일들만 매칭하고 싶다면 다음과 같이 제약 조건을 추가할 수 있습니다.
# 영문자만 매칭하도록 제한
letters_only, = glob_wildcards('letters-only-{name,[a-zA-Z]+}.txt')
# 결과: ['abc'] (abc-xyz는 하이픈 때문에, abc2는 숫자 때문에 제외됨)
# 숫자를 제외한 모든 문자 매칭하도록 제한
no_numbers, = glob_wildcards('letters-only-{name,[^0-9]+}.txt')
# 결과: ['abc', 'abc-xyz']제약 조건은 {와일드카드이름,정규표현식} 형태로 작성합니다.
하위 디렉터리 매칭 방지하기
glob_wildcards는 기본적으로 하위 디렉터리의 파일까지 모두 포함합니다. 예를 들어 data/datafile.txt라는 파일이 있다면 {filename}.txt 패턴은 data/datafile을 찾아낼 것입니다.
하지만 슬래시(/)를 매칭하지 않도록 제약 조건을 걸면 현재 디렉터리의 파일만 찾도록 제한할 수 있습니다.
# 슬래시(/)가 포함되지 않은 파일이름만 매칭 (현재 디렉터리만)
this_dir_only, = glob_wildcards('{filename,[^/]+}.txt')이 방식은 워크플로가 의도치 않게 다른 프로젝트의 파일이나 백업 디렉터리를 건드리지 않게 하는 데 매우 효과적입니다.
규칙(Rule) 내에서 와일드카드 제약 조건 사용하기
규칙의 input:이나 output: 블록에서도 동일한 문법을 사용할 수 있습니다. 와일드카드가 처음 언급되는 위치에 제약 조건을 명시하면 해당 규칙의 모든 부분에 적용됩니다.
rule sample_only:
output: "{sample,[A-Z]+}.out"
shell: "touch {output}"위 규칙은 sample 와일드카드가 대문자로만 이루어진 경우에만 실행됩니다.
전역 와일드카드 제약 조건
Snakefile 전체에서 특정 와일드카드 이름에 공통적으로 제약 조건을 적용하고 싶다면 wildcard_constraints: 블록을 사용합니다.
wildcard_constraints:
sample="\w+", # sample이라는 이름의 모든 와일드카드를 영문자/숫자로 제한
num="[0-9]+" # num이라는 이름의 모든 와일드카드를 숫자로 제한
rule a:
input: "{sample}.in" # 전역 제약 조건이 자동 적용됨
output: "{sample}.out"이렇게 하면 각 규칙마다 제약 조건을 반복해서 적을 필요가 없어 Snakefile이 훨씬 깨끗해집니다.