定义一个特殊的逐字命令

定义一个特殊的逐字命令

为了了解有关 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 解决方案。

  1. 参数按逐字类别代码 (12) 读取。Plain TeX 提供了 中的特殊字符列表\dospecials
  2. 参数被花括号包围。因此花括号会获得其通常的类别代码。然后参数可能包含匹配的花括号。但是,无法使用反斜杠转义花括号,因为反斜杠的类别代码为 12。

  3. 该参数被读取并存储在宏中\verbText

  4. \meaning打印宏定义。字符的类别代码为 12(其他),空格字符的正常类别代码为 10(空格)。

  5. 字体\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

转义结果

相关内容