charcode를 사용하여 토큰 목록에 문자 추가

charcode를 사용하여 토큰 목록에 문자 추가

문자 코드 표현에서 실제 문자 토큰을 얻을 수 있는 방법이 있습니까? 특히, \prepend#1#2토큰 목록을 가져와 #1문자 코드에 해당하는 문자 토큰을 앞에 추가하는 매크로를 갖고 싶습니다 #2.

다음은 원하는 결과에 대한 간단한 데모입니다.

\newtoks\test
\test={bc}
\prepend\test{97}
\showthe\test % should print abc

답변1

당신이 사용할 수있는 \char_generate:nn { <charcode> } { <catcode> }:

\input expl3-generic
\ExplSyntaxOn
\cs_new_eq:NN \toks_use:N \tex_the:D
\cs_new_protected:Npn \prepend #1 #2
  {
    \if:w \exp_not:N #1 #1
      \use:x { #1 = { \char_generate:nn {#2} { 12 } \toks_use:N #1 } }
    \else:
      \tl_put_left:Nx #1 { \char_generate:nn {#2} { 12 } }
    \fi:
  }
\ExplSyntaxOff

\newtoks\test
\test={bc}
\prepend\test{97}
\showthe\test % should print abc

\def\test{bc}
\prepend\test{97}
\show\test % should print abc

\bye

터미널 출력은 다음과 같습니다:

> abc.
l.16 \showthe\test
                   % should print abc
? 
> \test=macro:
->abc.
l.21 \show\test
                % should print abc again
?

캐릭터를 생성하는 방법은 \char_generate:nn사용 중인 엔진에 따라 다릅니다. LuaTeX에서는 tex.cprint(<catcode>, utf8_char(<charcode>))Henri의 답변과 비슷한 방식으로 사용 하지만 가능한 <catcode>설정이 있습니다. XeTeX에서는 \Ucharcat <charcode> <catcode>.

expl3( pdftex, ε-pTeX및 ) 이 지원하는 다른 엔진에서는 ε-upTeX실제로생성하다확장 전용 컨텍스트의 문자(의 핵심 기능 \char_generate:nn)이므로 expl3egreg의 답변과 동일한 접근 방식을 사용하여 이러한 문자를 미리 생성한 다음 \char_generate:nn요청 시 해당 문자를 사용합니다.

egreg의 답변에서와 같이 일부 catcode(즉, 0, 5, 9, 14 및 15)의 문자는 토큰을 생성하지 않기 때문에 생성할 수 없습니다(TeX가 입력을 스캔할 때 사라지므로 존재하지 않습니다). 거시적 확장 수준에서). 또한 expl3구현에서는 엔진 간 일관성을 위해 공백 문자 생성을 허용하지 않습니다. Lua 버전에서는 이를 허용하지 않기 때문입니다. 그러나 Knuth TeX 버전을 원하므로 공백 문자도 허용됩니다.


아래 코드는 Knuth TeX에서 작동하도록 수정된 expl3코드 를 적용한 것입니다. \char_generate:nn코드는 기본적으로 동일합니다. 주로 가 없기 때문에 몇 가지 더 복잡한 문제가 필요하다는 점을 제외하면 \unexpanded매크로에 단일 매개변수 토큰을 사용할 수 있고 toks 없이도 매크로에 항목을 쉽게 추가할 수 있습니다. 등록하다. 그 외에는 똑같습니다.

코드는 먼저 다음 ^^@으로 구분된 다양한 가능한 catcode와 함께 널 문자( )를 포함하는 임시 toks 레지스터를 정의합니다.\or

\or ^^@% 1
\or ^^@% 2
\or ^^@% 3
\or ^^@% 4
\or    % 5 Invalid
\or ^^@^^@% 6 Has to be doubled for a later `\def`
\or ^^@% 7
\or ^^@% 8
\or    % 9 Invalid
\or ^^@% 10
\or ^^@% 11
\or ^^@% 12
\or ^^@% 13

256그런 다음 모든 문자 코드를 반복하고 \lccodenull 문자를 다음으로 설정한 #1다음 \lowercaseegreg의 답변에서 트릭을 사용합니다.

    \begingroup
      \lccode0=#1
      \lccode32=#1
      \edef\x{\endgroup
      \gdef\expandafter\noexpand
        \csname c__char_\romannumeral#1_tl\endcsname{\the\tmptoks}}%
      \lowercase\expandafter{\x}

문자 코드(예: 97)의 경우 다음과 같은 결과가 발생합니다.

\gdef\c__char_xcvii_tl{\or a\or a\or a\or a\or \or aa\or a\or a\or \or a\or a\or a\or a}

그런 다음 문자 코드가 주어지면 를 사용하여 <charcode>해당 토큰 목록에 액세스할 수 있으며 \csname c__char_\romannumeral<charcode>_tl\endcsname`\ifcase\fi를 사용하면 요청한 문자를 갖게 됩니다.

매크로 \chargenerate는 먼저 \generateaux인수가 유효한 범위(5와 9를 제외하고 1에서 13 사이의 catcode, 0에서 255 사이의 charcode, Knuth TeX를 사용하면 이를 127로 변경해야 할 수도 있음)에 있는지 확인합니다(in ). \generateauxi인수를 사용하여 호출 한 다음 \ifcase위의 테스트(확장 제어를 위한 몇 가지 비트와 조각 포함)를 사용하여 요청된 문자를 남겨둡니다.

아래 코드를 실행하면 tex다음을 얻습니다.

여기에 이미지 설명을 입력하세요

% Auxiliaries
\long\def\gobbletoqstop#1\qstop{}
\long\def\firstofone#1{#1}
\chardef\expend=0
% Expandable error message
\begingroup
\long\xdef\expandableerror#1{%
  \noexpand\expandafter\noexpand\expandafter\noexpand\expandafter
    \noexpand\gobbletoqstop\noexpand\firstofone
      {\csname Error! \endcsname#1}\noexpand\qstop}
\endgroup
% Append stuff to a toks register
\def\toksputright#1{%
  \begingroup
    \def\toksputtoks{#1}%
    \afterassignment\toksputrightaux
    \toks0=}
\def\toksputrightaux{%
    \edef\x{\endgroup
      \toksputtoks={\the\toksputtoks\the\toks0}}%
  \x}
% Set up constant token lists
\newtoks\tmptoks
\begingroup
  \tmptoks{ \noexpand\or}%
  \catcode0=1
  \toksputright\tmptoks{^^@\iffalse}}%
  \catcode0=2
  \toksputright\tmptoks{{\fi\noexpand\or^^@}%
  \begingroup
    \def\noop{}%
    \edef\x{\expandafter\noop\the\tmptoks}%
  \expandafter\endgroup
  \expandafter\tmptoks\expandafter{\x}%
  \catcode0=3  \toksputright\tmptoks{\or^^@}%
  \catcode0=4  \toksputright\tmptoks{\or^^@}%
  \catcode0=5  \toksputright\tmptoks{\or}%
  \catcode0=6  \toksputright\tmptoks{\or^^@^^@}%
  \catcode0=7  \toksputright\tmptoks{\or^^@}%
  \catcode0=8  \toksputright\tmptoks{\or^^@}%
  \catcode0=9  \toksputright\tmptoks{\or}%
  \catcode0=10 \toksputright\tmptoks\expandafter{\firstofone{\or}^^@}%
  \catcode0=11 \toksputright\tmptoks{\or ^^@}%
  \catcode0=12 \toksputright\tmptoks{\or^^@}%
  \catcode0=13 \toksputright\tmptoks{\or^^@}%
  \def\chartmp#1;{%
    \begingroup
      \lccode0=#1
      \lccode32=#1
      \edef\x{\endgroup
      \gdef\expandafter\noexpand
        \csname c__chargen_\romannumeral#1_tl\endcsname{\the\tmptoks}}%
      \lowercase\expandafter{\x}}%
  \let^^L\relax
  \catcode`^^L=12
  \count0=0
  \loop
    \expandafter\chartmp\number\count0;
    \advance\count0 by 1
    \ifnum\count0<256 \repeat
\endgroup
% Main definition
\def\chargenerate#1#2{%
  \romannumeral\expandafter\generateaux
    \number#1\expandafter;\number#2;}
% Check for invalid input
\def\generateaux#1;#2;{%
  \ifnum0%
      \ifnum#1=0  1\fi
      \ifnum#2=10 1\fi
      =11
    \expandableerror{Cannot generate null char as a space.}%
  \else
    \ifodd0%
        \ifnum#2< 1 1\fi
        \ifnum#2= 5 1\fi
        \ifnum#2= 9 1\fi
        \ifnum#2>13 1\fi\space
      \expandableerror{Invalid catcode for char generation.}%
    \else
      \ifodd0%
          \ifnum#1<  0 1\fi
          \ifnum#1>"FF 1\fi\space
        \expandableerror{Charcode requested out of engine range.}%
      \else
        \generateauxi{#1}{#2}%
      \fi
    \fi
  \fi
  \expend}
% Actual char generation
\def\generateauxi#1#2#3\expend{%
  #3%
  \iffalse{\fi
  \expandafter\expandafter
  \expandafter\expend
  \expandafter\expandafter
  \ifcase#2%
    \csname c__chargen_\romannumeral#1_tl\endcsname
  \or}
  \fi}

% Testing
\def\empty{}
\begingroup
  \lccode`\~=`a
  \lowercase{\endgroup
  \gdef ~{\ active character a}%
}
\def\test#1{%
  \edef\x{%
    \ifnum#1=2 {\iffalse}\fi\space\noexpand\meaning\fi % add { if a is a }
    \chargenerate{97}{#1}%
    \ifnum#1=6 \chargenerate{97}{#1}\fi% add another # if a is a #
    \ifnum#1=1 \iffalse{\fi\space\noexpand\meaning}\fi % if a is a {, add a }
  }%
  \ifx\x\empty
    #1: ERROR
  \else
    #1: \expandafter\meaning\x
  \fi\par}

\tt\scrollmode
\count2=0
\loop
\test{\the\count2 }%
\advance\count2 by 1
\ifnum\count2<16
\repeat

\bye

답변2

\lowercaseTeX를 사용하여 이를 수행하는 좋은 방법입니다.

\def\prepend#1#2{% toks, charcode
 \begingroup
  \lccode`9=#2\relax
  \lowercase{%
    \edef\0{\endgroup 
       #1={9\the#1}}%
  \0}}

toks 레지스터가 가 아니라고 가정합니다 \0.

답변3

\newtoks\test

\def\prepend#1#2{%
  \ifcase\catcode#2\relax
    % 0, do nothing
    \or
    % 1, do nothing
    \or
    % 2, do nothing
    \or
    \prependaux#1{#2}{$}% 3
    \or
    \prependaux#1{#2}{&}% 4
    \or
    % 5, do nothing
    \or
    \prependaux#1{#2}{##}% 6
    \or
    \prependaux#1{#2}{^}% 7
    \or
    \prependaux#1{#2}{_}% 8
    \or
    % 9, do nothing
    \or
    \prependaux#1{#2}{ }% 10
    \or
    \prependaux#1{#2}{a}% 11
    \or
    \prependaux#1{#2}{?}% 12
    \or
    \prependaux#1{#2}{~}% 13
    % 14 or 15, do nothing
  \fi
}
\def\prependaux#1#2#3{%
  \begingroup\lccode`#3=#2\relax
  \lowercase{\endgroup\toks0={#3}}%
  #1\expandafter{\the\toks\expandafter0\the#1}%
}

\test={bc}
\prepend\test{97}

\message{\number`?}

\catcode`?=3

\prepend\test{63}

\the\test$

\prepend\test{`\#}

\showthe\test

\bye

카테고리 코드가 0, 1, 2, 5, 9, 14, 15인 캐릭터는 추가할 수 없습니다.

보시다시피, "이상한" 범주 코드 3 문자를 앞에 추가했고 코드는 \the\test$수학 공식을 인쇄합니다.

제한사항: #1일 수 없습니다 \toks0.

답변4

LuaTeX와 string.char함수를 사용하여 ASCII 코드를 해당 문자로 변환할 수 있습니다.

\newtoks\test
\test={bc}
\tokspre\test\expandafter{\directlua{tex.sprint(string.char(97))}}
\showthe\test
\bye

관련 정보