Q&A 마당은 텍 관련 질문/답변을 위해 만들었습니다.
- 로그인 없이 자유롭게 글을 읽고 쓸 수 있는 철학은 처음과 같이 계속됩니다.
- 질문 전에 아래를 읽어 보세요. 좋은 질문이 좋은 답을 받을 수 있는 좋은 방법입니다.
- 질문에 맞는 제목을 붙이세요. 질문의 내용과 관련없는 "고수님", "긴급질문", "도와주세요"와 같은 제목은 답이 잘 올라오지 않습니다. 이 게시판에 올라오는 모든 글은 질문입니다. 굳이 [질문], [Q]를 적으실 필요도 없습니다.
- 내용을 충실히 적어 주시고, 같은 상황을 재현할 수 있는 최소한의 예제가 같이 있어야 합니다.
- 최소 예제는 "Minimal working example"을 읽어 보세요.
- 파일을 첨부하실 때에는 가능한 압축하여 파일 크기를 줄여서 올려주시길 바랍니다.
- 개인적으로 사용하신 글꼴이 들어 있는 경우, preparefont.sty에 관한 답변을 참조하세요.
- 스팸 글을 막기 위하여 짧은 시간 내에 다시 글이 등록되는 IP를 막거나, 광고 글을 막기 위하여 금지어로 .com, .net 등을 설정하고 있습니다. 다소간의 불편함이 있으시더라도 양해 바랍니다.
- 금지어에서 stackexchange, stackoverflow, ctan, overleaf, , github, google.com, gmail.com, .org, .io, sil.org, wiki.com, tistory.com등은 해제하였습니다.
- MathJax를 이용한 수식조판을 사용하실 수 있습니다. 여기를 참조하세요.
- 사용하는 편집기는 CKeditor입니다.
- 편집기에서 [enter]를 누르면 <p> 태그가 들어가고, 문단으로 생각하고 한 줄을 비웁니다.
- 글줄만 바꾸려면 [shift-enter]를 누르면 <BR> 태그가 들어가므로 용도에 맞게 나누어 쓸 수 있습니다.
- 수식를 문서내에 삽입하시려면 에디터를 툴바에서 [소스]를 눌러 HTML로 입력할 수 있게 바꾸신 후 <pre> </pre> tag를 사용하셔서 <pre> 여러 줄의 수식 </pre>처럼 입력하시면 좋습니다.
l3regex 정규식 패턴으로 매크로를 사용할 때 \c를 사용해야 되는 이유?
2023.11.22 12:35
l3regex는 정규식 매칭할 때 매크로 확장을 하지 않고 "그대로" 비교한다고 알고 있습니다.
1. 그런데 아래 MWE에서 \SetDelim{\in}
이 아니라 \c{in}
으로 해야하는 이유가 무엇인가요?
2. 나아가서, \SetDelim
이 그냥 \SetDelim{\in}
으로 받게 하려면 (내부적으로 매크로들을 \c{_}
으로 변환하게) 어떻게 해야할까요? (가능하다면)
\documentclass{article}
\ExplSyntaxOn
\tl_new:N \l__delim_tl
\regex_new:N \l__delim_regex
\cs_generate_variant:Nn \regex_set:Nn { NV }
\NewDocumentCommand \SetDelim { m }
{
\tl_set:Nn \l__delim_tl { #1 }
}
\NewDocumentCommand \SplitText { m }
{
\regex_set:NV \l__delim_regex \l__delim_tl
\regex_split:NnN \l__delim_regex { #1 } \l_tmpa_seq
\seq_map_inline:Nn \l_tmpa_seq { \fbox{##1} }
}
\ExplSyntaxOff
\begin{document}
\SetDelim{\c{in}}
\SplitText{a\in A}
\end{document}
댓글 7
-
noname
2023.11.22 15:45
-
Zeta
2023.11.22 18:07
오! 항상 감사드립니다. 차근차근 이해하고 있는 중인데, 질문이 있습니다.
1.
\tl_count
가 1보다 클 때는 무조건 매크로가 아니라고 하는 논리인가요? 만약 제가 이해한 게 맞다면, 마지막\tl_reverse:N\l_tmptmp_tl
은 필요없는 것 아닌가요? 어차피 한 글자만 들어있다고 생각했습니다.2. 그리고 이렇게 하는 것은
\token_if_cs
가 토큰 하나만 먹고 나머지는 input stream에 놓기 때문인 것이 맞을까요?3. 사실
\tl_gset:Nx \l__delim_tl { { ...
부분이 어렴풋이밖에 이해가 안 됩니다.\use_i:nnn
는\cs_split_function:N
이 3부분으로 나누기 때문인 것은 이해했습니다. 그런데\exp_last_unbraced:Nf
가 왜 인자를 두 개만 받는지 잘 모르겠습니다.\exp_last_unbraced:Nf\use_i:nnn {\cs_split_function:N #1}
와 같이 뒤에 두 인자를 묶어야 하지 않나요? (이렇게 해도 돌아갑니다.)4. 3에서 이어지는데요, 그렇게 묶으면
\exp_last_unbraced:Ne
도 돌아가지만 묶지 않은 경우에는:Nf
만 돌아갑니다. 또한:Nx
는 어떻게 하든 안 돌아갑니다. interface3의 확장 부분을 여러 차례 읽어도 잘 와닿지 않습니다 ㅠㅠ5. 아마 3/4를 이해하면 이것도 깨닫겠지만..
\tl_gset:Nx \l__delim_tl {{...
에서 왜 시그니처가:Nx
인가요? 이게 어디까지 확장하고 그치는지 그려지지가 않네요..긴 질문 읽어주셔서 감사합니다. TeX의 길은 참 멀군요..
-
noname
2023.11.22 18:20
1: 말씀하신 것이 맞습니다. 제 의도는 마지막 토큰 한 개만 챙기겠다는 것이었는데 약간 이상하게 되어 있었네요. 고쳤습니다.
2: \token_if_cs:N으로 cs인지를 검사하는데 딱 하나의 토큰만 먹기 때문입니다. 그게 N이죠. 이게 cs이면 T이고 아니면 F인데, 예를 들어 인자 #1로 "out"이 들어왔다고 할 때, 이대로 이 검사에 먹이면 o만으로 검사하고 "ut"는 그대로 i/s에 남게 됩니다. 예상하시는 대로입니다. 그래서 한 개의 토큰만을 추려내려고 한 것입니다.
3부터는 잠시 후에... 답글을 달겠습니다.
-
Zeta
2023.11.22 18:31
ㅎㅎ 넵 이해했습니다 감사합니다!!!
-
noname
2023.11.22 18:57
... 그리고 잠시후...
3: f확장의 가장 큰 효용(장점)은 주어진 위치에서 하나의 매크로만 x확장할 수 있다는 것입니다. x확장을 쓰지 않는 이유는 \cs_split_function:N의 인자로 주어지는 function을 "실행"하지 않기 위해서입니다. \exp_last_unbraced:Nf \use_i:nnn 다음에 매크로가 연이어 두 개 나오는데, f확장은 \cs_split_function:N은 "확장"되고 그 뒤에 나오는 매크로는 확장되지 않습니다. 함수의 정의에 따라 그 뒤에 나오는 N 하나를 이 함수의 인자로 처리합니다. x확장을 하면 주어진 위치의 함수가 취하는 N인자까지도 확장할 것이므로 이 맥락에서는 에러가 뜨겠죠.
"두 인자를 묶어야 하지 않나요?"에 대해서는, 만약 그렇게 줄 것이라면 \exp_last_unbraced:가 아니라 \exp_args로 하는 게 낫겠습니다. 이 경우라면 두 개가 큰 차이 없이 실행될 듯도 합니다만.
\cs_split_function:N은 인자로 주어지는 함수를 (1) 함수 이름 (2) 인자지시부 (3) 임의의 토큰(스페이스)으로 나누기 때문에 (임의의 토큰은 \endcsname을 의미하는 space이거나, 혹은 있을지도 모르는 콜론입니다), 보통의 매크로라면 first of three로 이름을 얻을 수 있습니다. \use_i:nnn은 \@firstofthree와 거의 같습니다.
4: 3에서 대략 설명이 된 듯합니다.
5: 만약 여기서 :Nn으로 한다면 \l__delim_tl에는 {\exp_last_unbraced:Nf ... }하는 매크로들이 그대로 들어가 있습니다. 이것을 x확장해주어야 이 매크로가 모두 실행된 결과인 value가 \l__delim_tl에 들어가게 되겠죠. #1이 있는데 왜 괜찮은가 하면, \tl_gset:이 불리기 전에, 즉 이 명령(\SetDelim)이 불리는 시점에 #1은 이미 교체되어 있기 때문입니다. 아무튼
\SetDelim{\in}
이라고 하면, 결과적으로
\l__delim_tl ===> {in}
이 되게 하기 위한 것입니다.
===
중요한 것은 아니지만 \l__delim_tl은 \g__delim_tl이 나은 명명이었을까요?
-
noname
2023.11.22 20:18
예전 expl3 공부모임을 위해 준비했던 것 중에 (실제 사용하지 않은) 첨부 파일과 같은 것이 있네요. 혹시나 참고가 될지 몰라서 첨부해둡니다.
-
Zeta
2023.11.22 21:12
오오!! 감사합니다 ㅎㅎ 잘 공부해보겠습니다.
\(backslash)는 regex의 escape character입니다. 즉 예를 들어 \a를 매치하려면 \\a로 해야 합니다. 그리고 interface3에 잘 나와 있는 바와 같이 \\a는 문자 \와 문자 a를 의미하지 TeX의 control sequence를 의미하지 않습니다. TeX cs는 반드시 \c{...}로 쓰라고 하고 있죠. 텍 매크로 \in 은 의미상 {control sequence: i n}인 것이지 {characters: \\ i n}이 아니기 때문입니다.
(그래서 백슬래시 두 개로 이루어진 명령 \\은 \c{\\}로 매치해야 할 겁니다.)
regex만을 사용해서 예시된 명령을 완성해본다면 (여러 방법이 있을 것이므로 그냥 참고만 하십시오), 다음처럼 하면 대략 의도대로 동작할 듯도 합니다. 핵심 아이디어는 인자로 들어온 매크로에서 이름 부분(\를 제외한)을 추려내고 나중에 \c를 덧붙여준다는 것입니다.