%EC%A0%95%EC%9D%98%ED%95%A0%20%EC%88%98%20%EC%97%86%EB%8A%94%20%ED%86%A0%ED%81%B0%EC%9D%B4%20%EC%9E%88%EC%8A%B5%EB%8B%88%EA%B9%8C%3F.png)
\uppercase
/ 에 영향을 받지 \lowercase
않고 에 대해 (재)정의할 수 없는 토큰이 있습니까 \outer
?
\uppercase
(그렇다면 / 안에 사용할 수 있는 항목에 대해 인수 구분 기호로 사용하고 싶습니다 \lowercase
.)
답변1
Afaik 해당 토큰이 없습니다.
각 토큰은 다음 두 가지 토큰 클래스 중 하나 이상에 속합니다. 활성 캐릭터 토큰은 두 클래스에 동시에 속합니다.
- 제어 순서. (제어 단어 토큰, 제어 기호 토큰, 활성 문자 토큰.) 모든 제어 시퀀스는
\outer
. - 명시적 문자 토큰. 각 명시적 문자 토큰은
\uppercase
/ 에 의해 영향을 받을 수 있습니다\lowercase
(\uccode
/ 가\lccode
적절하게 설정된 경우).
대부분의 경우 무제한 인수를 사용하고 비어 있는지 확인함으로써 구분된 인수를 완전히 피할 수 있습니다.
예를 들어 중괄호 균형 토큰 목록에서 첫 번째 무제한 인수를 추출하기 위해 나는 종종 다음과 같은 것을 사용합니다.
%% \romannumeral\UD@ExtractFirstArgLoop{<argument>\UD@SelDOm}%
%% yields <argument>'s 1st undlimited argument.
%% <argument> must not be blank, i.e., must neither be empty nor consist
%% only of explicit character tokens of catcode 10 and charcode 32.
%%
%% \UD@SelDOm must not be defined in terms of \outer !
%%.............................................................................
\@ifdefinable\UD@RemoveTillUD@SelDOm{%
\long\def\UD@RemoveTillUD@SelDOm#1#2\UD@SelDOm{{#1}}%
}%
\newcommand\UD@ExtractFirstArgLoop[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\@firstoftwo{}#1}%
{\expandafter\z@\@secondoftwo{}#1}%
{\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillUD@SelDOm#1}}%
}%
( \UD@CheckWhetherNull
다음과 같이 정의됩니다.
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral\expandafter\@secondoftwo\string{\expandafter
\@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
\@secondoftwo\string}\expandafter\z@\@secondoftwo}%
{\expandafter\z@\@firstoftwo}%
}%
또는
\newcommand\UD@CheckWhetherNull[1]{%
\romanumeral\ifcat$\detokenize{#1}$%
\expandafter\expandafter\expandafter\z@\expandafter\@firstoftwo\else
\expandafter\expandafter\expandafter\z@\expandafter\@secondoftwo\fi
}%
. )
이를 통해 다음을 얻을 수 있습니다.
\romannumeral\UD@ExtractFirstArgLoop{{A}{B}CDE\UD@SelDOm}%
→ A
.
구분되지 않은 첫 번째 인수를 제외한 모든 항목을 제거하는 데 필요한 반복 횟수를 줄이기 위해 로 구분된 인수를 사용했습니다 \UD@SelDOm
. (필요한 반복 횟수는 " \UD@SelDOm
중괄호 안에 중첩되지 않은 인수 내 횟수"+1입니다.)
\UD@SelDOm
로 정의된 -delimiter가 마음에 들지 않으면 \outer
다음과 같이 하지 않고 수행할 수 있습니다. 단, 결과를 얻을 때까지 더 많은 반복이 필요합니다. 필요한 반복 횟수는 다음과 같습니다. 자신이 중괄호 안에 중첩되지 않은 인수 내에서"+1:
% Syntax now is: \romannumeral\UD@ExtractFirstArgLoop{<argument>{}}%
\newcommand\UD@GrabFirst[2]{{#1}}%
\renewcommand\UD@ExtractFirstArgLoop[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\@firstoftwo{}#1}%
{\expandafter\z@\@secondoftwo{}#1}%
{\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@GrabFirst#1}}%
}%
예:
\romannumeral\UD@ExtractFirstArgLoop{{A}{BC}DE{}}%
→A
구분된 인수를 완전히 피하기 위해 유사한 작업을 수행할 수 있는 상황이 많이 있습니다.
때때로 사람들은 문제의 인수를 처리하는 매크로 토큰을 인수 구분 기호로 사용합니다(예: ) \def\macro#1\macro{...}
. 이것이 실현 가능/합리적인지 여부는 \macro
자체 인수 내에 중첩되어 구분 기호를 잘못 일치시킬 수 있는지 또는 이와 유사한 일이 \let\macrob=\macro \outer\def\macro...
발생할 수 있는지 여부 에 대한 질문에 따라 달라집니다 .
\outer\def...
매크로 인수를 안전하게 만드는 방법에 대해 이미 생각하고 있으므로 및 \uppercase
/ 외에 다른 함정이 있다는 점에 주목하고 싶습니다 \lowercase
.
예를 들어 사용자가 제공한 (거의) 임의의 인수를 처리하는 구분된 인수를 기반으로 하는 매크로 메커니즘이 테이블 형식 환경/정렬 내에서 작동해야 하는지 여부에 대한 질문입니다.
예를 들어 구분된 인수를 처리
\grabdelimited
하고 사용자가 문자를 수집하고 토큰화 해제하는 데 사용하는 매크로를 가정합니다B
.&
\documentclass{article} \def\grabdelimited#1\delimiter{Arguments grabbed: \detokenize{#1}}% \begin{document} \grabdelimited B&\delimiter \makeatletter \begin{tabular}{|l|l|} %A&\relax\grabdelimited B&\delimiter\\ A&\relax\expandafter\@firstofone\expandafter{\grabdelimited B&\delimiter} \end{tabular} \end{document}
tabular-environment 내부의 첫 번째/주석 처리된 줄은 오류를 생성하지만, 두 번째 줄은 여기서
&
구분된 인수에 속하는 것이 중괄호 안에 숨겨져 있기 때문에 오류가 발생하지 않습니다\@firstofone
.또 다른 문제는 불균형한 인수를 처리하는 매크로 정의에서 발생하는 일부와 잘못 일치할 수 있는 매크로 인수를
\if...
/\else
/ 전달하는 것일 수 있습니다.\fi
\if...
\else
\csname
불균형 / 과 동일합니다\endcsname
.
답변2
확장된 설명:
인수 끝 표시가 \uppercase
/ 의 영향을 받을까 두려운 경우에는 또는 \lowercase
에서 볼 수 없도록 최상위 수준에 표시되지 않도록 해야 합니다 . 이는 확장 컨텍스트를 사용하는 등 확장이 중간에 멈출 수 없는 컨텍스트에만 삽입되도록 함으로써 달성할 수 있습니다 . 다음은 문자를 인수 끝 표시로 사용하는 매크로를 설정 하지만 더 확장되므로 입력 스트림에 표시가 남아 있지 않아 또는 의 영향을 받을 수 없습니다 .\uppercase
\lowercase
\romannumeral
D
\lowercase
\uppercase
% first insert a \romannumeral such that the following is expanded as far as possible
\newcommand*\mymacro{\romannumeral\mymacro@a}
% only after \romannumeral has started input the delimiter
\newcommand\mymacro@a[1]{\mymacro@b #1D}
그런 다음 \mymacro@b
확장 가능한 방식으로 인수를 처리하고 D
구분 기호로 사용할 수 있습니다. 그리고 \romannumeral
확장 컨텍스트를 \z@
. 물론 \mymacro
한 번 확장한 다음 시작하지 않고 확장 \mymacro@a
하여 (with ) 의 영향을 받을 수 있지만 적어도 지금은 악의적인 의도로 생성해야 합니다.\expandafter
\romannumeral
D
\lowercase
\expandafter\expandafter\expandafter\lowercase\expandafter\expandafter\expandafter{\expandafter\expandafter\mymacro{}}
재정의 로부터 자신을 보호할 수는 없지만 \outer
다른 사람의 코드 내부를 재정의하는 사람들은 \outer
작동하는 코드를 원하지 않는 것 같으므로 자신을 보호해야 할 경우는 아닐 수도 있습니다.