- TRRE는 정규 표현식에 텍스트 변환을 직접 표현하는
:연산자를 추가한 언어 확장이며, 이를 실험하는grep -E유사 CLI 도구trre로 제공됨 - 기본 형태는
a:b처럼 입력 패턴을 출력 패턴으로 바꾸는 transductive pair이며, 삭제는x:, 삽입은:x처럼 빈 문자열과의 변환으로 표현함 - 일반 정규 표현식처럼 대안 선택, 반복, 문자 범위 변환을 사용할 수 있고,
cat:dog,[a:A-z:Z], Caesar cipher 같은 예제가 포함됨 - 내부 구현은 일반 정규 표현식의 FSA 대신 입력-출력 쌍을 다루는 Finite State Transducer(FST) 를 구성하며, 실험적인 on-the-fly 결정화도 지원함
- 현재는 사전 빌드 바이너리가 없고 직접 빌드해야 하며, DFT 안정화, Unicode 전체 지원, ERE 기능 완성, 효율적인 범위 처리 등이 TODO로 남아 있음
TRRE가 해결하려는 문제
- 일반 정규 표현식은 텍스트에서 패턴을 찾는 데 유용하지만, 텍스트 편집에서는 그룹 처리 로직이 후처리처럼 동작해 복잡해질 수 있음
- TRRE는 패턴 매칭과 텍스트 수정을 같은 표현식 안에 넣기 위해 정규 표현식 언어를 확장함
- 핵심 문법은
pattern-to-match:pattern-to-generate형태이며, 가장 단순한 예시는a:b로a를b로 바꿈 - CLI 도구
trre는 이 개념을 보여주는 구현체이며grep -E와 비슷한 느낌으로 동작함
기본 변환 문법
- 문자열 치환은
cat:dog처럼 작성함echo 'cat' | ./trre 'cat:dog'는dog를 출력함(c:d)(a:o)(t:g)처럼 문자 단위 변환으로도 같은 결과를 만들 수 있음
sed처럼 문자열 안의 모든 매치를 바꾸는 데 사용할 수 있음Mary had a little lamb.에서lamb:cat을 적용하면Mary had a little cat.이 됨
- 삭제는 오른쪽을 비워
string_to_delete:형태로 표현함(x:)or는xor에서x를 제거해or를 만듦a:는 기본 scan mode에서 모든a를 빈 심볼로 바꿔 제거함[aie]:처럼 대괄호 표현을 써 여러 문자를 제거할 수 있음
- 삽입은 왼쪽을 비워
:string_to_insert형태로 표현함(:x)or는or앞에x를 넣어xor를 만듦had a (:little )lamb는 문맥 안에서little을 삽입함
정규 표현식 위의 변환
- TRRE는 일반 정규 표현식처럼
|를 이용한 대안 선택을 지원함(c:b)at|(d:h)og는cat dog를bat hog로 바꿈
- 반복 연산자도 변환에 적용할 수 있음
(cat:dog)*는catcatcat을dogdogdog로 바꿈- 기본 scan mode에서는
cat:dog만으로도 반복 적용되어 같은 결과를 만들 수 있음
- 왼쪽 패턴에서 반복을 사용하면 여러 입력을 소비하고 하나의 출력으로 바꿀 수 있음
(cat)*:dog는catcatcat을dog로 바꿈
- 오른쪽 패턴에서
*나+를 쓰면 무한 루프가 발생할 수 있음:a*같은 표현식은 피해야 함- 유한 반복이 필요하면
:(repeat-10-times){10}처럼 횟수를 지정함
범위 변환과 생성기
- 문자 범위 변환은
[a:A-z:Z]처럼 작성함regular expressions를REGULAR EXPRESSIONS로 바꿀 수 있음
- Caesar cipher 예제가 포함됨
[a:b-y:zz:a]는caesar cipher를dbftbs djqifs로 바꿈[a:zb:a-z:y]는 이를 다시caesar cipher로 되돌림
- generator처럼 하나의 입력에서 여러 출력을 만들 수도 있음
- 기본값은 가능한 첫 번째 매치를 사용함
-a옵션을 쓰면 가능한 모든 출력을 생성함
- 예시로 빈 입력에
:(0|1){3}을 적용하면000부터111까지 3비트 이진 시퀀스를 만들 수 있음 :(0|1){,3}?와-ma를 함께 쓰면 길이 3 이하의 부분 집합 형태 출력들을 생성함
언어 사양과 연산자 우선순위
- 비공식적으로 TRRE는
pattern-to-match:pattern-to-generate쌍으로 정의됨 - 왼쪽
pattern-to-match는 문자열 또는 정규 표현식일 수 있음 - 오른쪽
pattern-to-generate는 보통 문자열이지만 정규 표현식도 가능함 :연산자는 현재 비결합적으로 취급되며,TRRE:TRRE형태는 문법적으로 허용되지 않음- 이 형태는 TRRE가 정의하는 관계의 합성이라는 자연스러운 의미가 있지만, 복잡도가 커질 수 있어 아직 제외됨
- 연산자 우선순위는 높은 순서부터 다음과 같음
- 이스케이프 문자
\ - 대괄호 표현
[] - 그룹화
() - 반복
* + ? {m,n} - 연결
- Transduction
: - 대안 선택
|
- 이스케이프 문자
모드와 탐욕성
trre는 두 가지 모드를 지원함- Scan Mode: 기본 모드이며 변환을 순차적으로 적용함
- Match Mode:
-m플래그를 사용하며 전체 문자열이 표현식과 맞는지 확인함
-a옵션은 가능한 모든 출력을 생성함?수정자는*,+,{,}연산자를 non-greedy로 만듦<(.:)*>는<cat><dog>에서<>를 출력함<(.:)*?>는 같은 입력에서<><>를 출력함
- 태그나 괄호 안의 내용을 바꾸는 예시도 포함됨
<(.*?:cat)>는<dog> <mouse>를<cat> <cat>으로 바꿈
FST 기반 구현과 결정화
- TRRE는 내부적으로 Finite State Transducer(FST) 를 구성함
- FST는 일반 정규 표현식에서 쓰는 Finite State Automaton(FSA) 와 유사하지만, 단순 문자열 대신 입력-출력 쌍을 다룸
- TRRE의 핵심 차이는 다음과 같음
- 두 정규 언어 사이의 이항 관계를 정의함
- 추론에 FSA 대신 FST를 사용함
- 성능을 위해 실험적인 on-the-fly 결정화를 지원함
- 일반 정규식 엔진에서 결정화는 비결정 오토마타를 결정 오토마타로 바꿔 입력 문자열 길이에 대해 선형 시간 추론을 가능하게 함
- TRRE에서도 비슷한 접근이 가능하지만, 모든 비결정 변환기 NFT를 결정 변환기 DFT로 바꿀 수는 없음
- 같은 입력 라벨을 가진 두 개의 “bad” cycle이 있으면 상태 생성이 무한 루프에 빠질 수 있음
- 이런 루프를 감지하는 방법은 있지만 비용이 큼
성능과 설치 상태
- 기본 비결정 버전은 단순 치환에서
sed보다 약간 느린 예시가 제시됨./trre '(vodka):(VODKA)': real0m0.046ssed 's/vodka/VODKA/': real0m0.024s
- 복잡한 작업에서는 결정 버전
trre_dft가sed보다 빠른 예시가 있음sed -e 's/\(.*\)/\U\1/': real0m0.508s./trre_dft '[a:A-z:Z]': real0m0.131s
- 사전 빌드 바이너리는 아직 제공되지 않음
- 설치는 저장소를 클론한 뒤
make && sh test.sh로 빌드하고 테스트하는 방식임 - TODO에는 다음 항목이 남아 있음
- 안정적인 DFT 버전
- 전체 Unicode 지원
- ERE 기능 완성
[]안의 부정^- 문자 클래스
$^앵커 심볼
- 효율적인 범위 처리
참고한 접근
- 정규 표현식 매칭 접근은 Russ Cox의 Regular Expression Matching Can Be Simple And Fast에서 강하게 영감을 받음
- transducer 결정화 아이디어는 Cyril Allauzen, Mehryar Mohri의 Finitely Subsequential Transducers에서 가져옴
- 파싱 접근은 Erik Eidt의 Double-E algorithm을 사용하며, 고전적인 Shunting Yard algorithm과 가까움