有什麼方法可以從字元代碼表示中取得實際的字元標記嗎?我特別想要一個宏\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
),所以expl3
使用與egreg的答案相同的方法預先生成這些字符,然後\char_generate:nn
在需要時使用這些字符。
正如egreg的回答一樣,您無法產生某些catcodes的字元(即0、5、9、14和15),因為它們不會產生標記(當TeX掃描輸入時它們會消失,因此它們不存在)宏觀擴張層面)。另外,expl3
實作不允許產生空格字元以保持跨引擎的一致性,因為 Lua 版本不允許這樣做。然而,由於您想要 Knuth TeX 版本,因此也允許使用空格字元。
下面的程式碼是對expl3
程式碼的改編,經過\char_generate:nn
修改後可以在 Knuth TeX 中工作。程式碼基本上相同,只是由於缺乏\unexpanded
,它允許您在巨集中擁有單一參數標記,並且允許您輕鬆地將內容附加到巨集而不需要 toks登記。除此之外,都是一樣的。
程式碼首先定義一個臨時 toks 暫存器,其中包含空字元 ( ^^@
) 以及不同的可能的 catcode,以 分隔\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
設定為,然後使用egreg的答案中的技巧:\lccode
#1
\lowercase
\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
)參數是否在有效範圍內(catcode 介於1 到13 之間,5 和9 除外,charcode 介於0 到255 之間,但使用Knuth TeX 時您可能需要將其變更為127),然後使用參數進行調用\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
\lowercase
對於任何 TeX 來說,這是一個很好的方法。
\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