![定义一个特殊的逐字命令](https://linux22.com/image/291895/%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E7%89%B9%E6%AE%8A%E7%9A%84%E9%80%90%E5%AD%97%E5%91%BD%E4%BB%A4.png)
为了了解有关 Plain TeX 的更多信息,我尝试定义一个特殊的逐字命令\verb{code}
,它将内容放在code
括号内。
当没有括号时code
,这很容易。但是当有一些均衡括号内code
,似乎很难定义这个命令。
此外,里面可能还有一些\{
或。我该如何定义它?\}
code
例如我想\verb{a{b\}c\{d}e}
生产a{b\}c\{d}e
。
答案1
以下是更简单的解决方案:
\newcount\tmpnum
\def\catcodeletters{\tmpnum=64
\loop \advance\tmpnum by1
\ifnum\tmpnum<128
\ifnum\catcode\tmpnum=11 \catcode\tmpnum=12 \fi
\repeat
}
\def\verb{\bgroup\catcode`\%=12\catcode`\^=13\catcode`\ =12\catcode`\#=12
\catcodeletters\verbA}
\def\verbA#1{\def\tmp{#1}\tt\expandafter\mm\meaning\tmp\endmm\tmp\egroup}
\def\mm#1->#2\endmm{\def\tmp{#2}}
\verb{a{b\}c\{d}e a #sp_&ace}
\end
我已将 添加\catcodeletters
到我的宏中,以便后面\foo
不会出现空格。感谢 Heiko。
编辑:我的 12 行宏没有被选为可接受答案,但 50 行宏被选为可接受答案。可能是用真实空格替换空格标记是兴趣的核心,但问题中没有指定。这是打印的一部分,不是逐字扫描。因此它可以在\tmp
扫描后实现。您可以更改\verbA
定义,也可以添加\printverb
宏,它以不同于上一个答案的方式进行空格替换。
\def\verbA#1{\def\tmp{#1}\expandafter\mm\meaning\tmp\endmm
\tt\expandafter\printverb\tmp\end\egroup}
\def\printverb{\futurelet\next\printverbA}
\def\printverbA{%
\ifx\next\end \def\next{\let\next}%
\else \ifx\next\spacetoken \char32
\def\next{\afterassignment\printverb\let\next= }%
\else \next \def\next{\afterassignment\printverb\let\next}%
\fi \fi
\next
}
\edef\tmp{\let\noexpand\spacetoken= \space}\tmp
现在\tt\char32
打印的是空格标记而不是空格。
答案2
不含 e-TeX 的普通 TeX 解决方案。
- 参数按逐字类别代码 (12) 读取。Plain TeX 提供了 中的特殊字符列表
\dospecials
。 参数被花括号包围。因此花括号会获得其通常的类别代码。然后参数可能包含匹配的花括号。但是,无法使用反斜杠转义花括号,因为反斜杠的类别代码为 12。
该参数被读取并存储在宏中
\verbText
。\meaning
打印宏定义。字符的类别代码为 12(其他),空格字符的正常类别代码为 10(空格)。字体
\tentt
有一个特殊的空格字符,但该空格需要不同的 catcode。这是通过宏完成的\ConvertSpacesToCatcodeOther
。
示例文件:
\def\verb{%
\begingroup
% verbatim catcodes
\def\do##1{\catcode`##1=12 }%
\dospecials
% except curly braces
\catcode`\{=1 %
\catcode`\}=2 %
\verbAux
}
\def\verbAux#1{%
\def\verbText{#1}%
\edef\verbText{%
\expandafter\StripPrefix\meaning\verbText
}%
\tentt
\FirstOfOne{\expandafter\ConvertSpacesToCatcodeOther\verbText} \NIL
\endgroup
}
\def\StripPrefix#1>{}
\long\def\FirstOfOne#1{#1}
\def\ConvertSpacesToCatcodeOther#1 #2\NIL{%
#1%
\def\temp{#2}%
\ifx\temp\empty
\expandafter\Gobble
\else
\SpaceOther
\expandafter\FirstOfOne
\fi
{\ConvertSpacesToCatcodeOther#2\NIL}%
}
\long\def\Gobble#1{}
\begingroup
\lccode`\9=32 % space
\lowercase{\endgroup
\def\SpaceOther{9}%
}
\verb{a{b\}c\{d}e with spaces}
\bye
转义
还可以实现使用反斜杠对花括号进行转义。如果反斜杠有其转义类别代码 (0),则命令名称将照常进行标记。\meaning
将在由字母类别代码 (11) 的字符组成的命令名称后添加一个空格。\abc
将变为\abc␣
。可以通过更改所有字母的类别代码来避免这种情况:
\def\verb{%
\begingroup
% verbatim catcodes
\def\do##1{\catcode`##1=12 }%
\dospecials
% except curly braces and backslash
\catcode`\\=0 %
\catcode`\{=1 %
\catcode`\}=2 %
\count255=`\A %
\loop
\catcode\count255=12 %
\ifnum\count255<`\Z %
\advance\count255 by 1 %
\repeat
\count255=`\a
\loop
\catcode\count255=12 %
\ifnum\count255<`\z %
\advance\count255 by 1 %
\repeat
\verbAux
}
\def\verbAux#1{%
\def\verbText{#1}%
\edef\verbText{%
\expandafter\StripPrefix\meaning\verbText
}%
\tentt
\FirstOfOne{\expandafter\ConvertSpacesToCatcodeOther\verbText} \NIL
\endgroup
}
\def\StripPrefix#1>{}
\long\def\FirstOfOne#1{#1}
\def\ConvertSpacesToCatcodeOther#1 #2\NIL{%
#1%
\def\temp{#2}%
\ifx\temp\empty
\expandafter\Gobble
\else
\SpaceOther
\expandafter\FirstOfOne
\fi
{\ConvertSpacesToCatcodeOther#2\NIL}%
}
\long\def\Gobble#1{}
\begingroup
\lccode`\9=32 % space
\lowercase{\endgroup
\def\SpaceOther{9}%
}
\verb{a{b\}c\{d}e with spaces \abc\} \{}
\bye