Scantokens 和 Let

Scantokens 和 Let

inputenc例如,该包可以编写°代码来打印度数符号。简单一点,它通过使其成为活动字符(catcode 13)并定义相应的宏来实现。如果将其类别更改为其他(catcode 12),然后使用 更改回\scantokens,它会继续打印度数符号。由于我需要打印一个字符串,一次一个字符,包括空格,所以我的第一个想法是使用\let

\documentclass{article}
\usepackage[ansinew]{inputenc}
\usepackage[T1]{fontenc}

\begin{document}
\setlength\parindent{0pt}

A°@ 1

{\catcode`\°12 \xdef\str{A°@ 1}}
\str

\scantokens\expandafter{\str\empty}

\def\aaa{\afterassignment\bbb\let\ccc= }
\def\bbb{%
  \ifx\ccc\nil
     END
     \let\next\relax
  \else
     [\scantokens\expandafter{\ccc\empty}]\let\next\aaa
  \fi
  \next
}
\expandafter\aaa\str\nil

\end{document}

其输出为:

输出第一个例子

不幸的是,正如 jfbu 指出的那样,\scantokens对角色没有任何作用\let,因此它会打印[ř]而不是[°]。为了使其明显,请考虑以下内容:

\documentclass{article}
\usepackage[ansinew]{inputenc}
\usepackage[T1]{fontenc}

\begin{document}
\setlength\parindent{0pt}

{\catcode`\°12 \gdef\ddd{°} \global\let\eee°}

[\ddd] - [\scantokens\expandafter{\ddd\empty}]

[\eee] - [\scantokens\expandafter{\eee\empty}]

\end{document}

其输出为:

输出第二个示例

当然,在第一个例子中,一个可能的解决方案是将\scantokens方括号中的替换为\ifx\ccc\ddd°\else\ccc\fi,并注意{\catcode`\°12 \global\let\ddd°}在开头添加。这种方法的问题在于它不太“可扩展”。

我在这里的真正目标是解析一些(CP-1252 编码的)文件,这些文件可以包含任何字符,而不仅仅是°。为了将其放在上下文中并为了简单起见,我们假设我正在用 (La)TeX 编写十六进制查看器(顺便说一句,这不是一个坏主意)。

因此,对于文本部分,我首先用类似的内容“加载”文件\edef\fff#1{\pdfunescapehex{\pdffiledump length \pdffilesize{#1}{#1}}},它给出所有带有 catcode 12 的字符标记,除了空格(具有 catcode 10);然后我扫描这样的标记列表并根据需要采取行动,打印它,否则。

那么,有没有一种方法可以扫描包括空格在内的标记列表而不使用\let?将 catcode 12 也分配给空格就足够了,我可以这样做吗?怎么做?或者,有没有一种方法可以在 之后更改 catcode \let,而不涉及大量条件表达式?如果没有,最好的(紧凑和/或优雅)方法是什么?

答案1

当您执行时,\let\ccc=它将“让”\ccc代表连续的标记,而它们实际上在您的\str宏内容中都是不可扩展的。因此什么\expandafter{\ccc也不做。然后什么\scantokens也不做,因为它看到\ccc,它看不到°标记。顺便说一句,您不需要\xdef您的\str定义,因为没有什么可以扩展的,因为您已经分配了\catcode12°在cp1252代码页中,字符代码是176,这给出了T1字体编码。)

在此处输入图片描述


更新原始问题后。但我仍然不太清楚上下文到底是什么。下面是如何解析每个字符的字符,这很容易,因为除了空格之外的所有内容都是 catcode 12。我要做的是定义\@namedef{mymeaning<char>}特殊事物的宏(其中<char>是一个 catcode 12 标记,也许使用\ifdefined,其他的\scantokens可以一般使用。在这里我使用并将\meaning反斜杠和百分比分开,因为\scantokens在字符上没有用。

这是仅 8 位编码方法。我用 进行说明。此外,由于该方法,iso-latin-1没有标记。\par\pdffiledump

并且该文件使用 unix 行尾。

% -*- coding:iso-latin-1; -*-
\documentclass{article}
\usepackage[latin1]{inputenc}

\def\ParsePerWord #1 {\ifx\ignorespaces#1\ignorespaces
                         <SPACE>\par
                         \expandafter\ParsePerWord
                      \else
                         \if\relax#1\else
                            \ParsePerChar #1\relax
                            \expandafter\expandafter\expandafter\ParsePerWord
                         \fi
                      \fi}
\def\ParsePerChar #1{\if\relax#1\bigskip % end of "word"
                     \else
                        \ifnum`#1=10 % unix end of line
                          <EOL>\par
                        \else
                          \ifnum`#1=92 % backslash
                             <BACKSLASH>\par
                          \else
                             \ifnum`#1=37 % percent
                                 <PERCENT>\par
                             \else
                                 \scantokens{\meaning #1}\par
                             \fi
                          \fi
                        \fi
                        \expandafter\ParsePerChar
                      \fi}

\begin{document}

éà°§ù"£{$\Omega$}\def\x#1{&}

\edef\fff{\pdfunescapehex{\pdffiledump offset 1198 length 100{\jobname.tex}}}

\show\fff

\ttfamily

\makeatletter
\@firstofone{\@firstofone{\expandafter\ParsePerWord\fff} \relax} %

\end{document}

在此处输入图片描述


在上文中,一​​些空格(分隔“单词”的空格)通过 呈现\bigskip,而其他空格(例如,行首的空格)通过 呈现<SPACE>\par

最好执行以下操作

\def\ParsePerWord #1 {\ifx\ignorespaces#1\ignorespaces
                         <SPACE>\par
                         \expandafter\ParsePerWord
                      \else
                         \if\relax#1%
                            <END OF DUMP>\par % <<-- CHANGED !
                         \else
                            \ParsePerChar #1\relax
                            <SPACE>\par %       <<-- CHANGED !
                            \expandafter\expandafter\expandafter\ParsePerWord
                         \fi
                      \fi}
\def\ParsePerChar #1{\if\relax#1% end of "word" <<-- CHANGED !
                     \else
                     .... etc ....

它会打印<SPACE>\par输入中的所有空格字符。我还添加了一个<END OF DUMP>\par(并删除了\bigskip)。

但问题是最后一个<SPACE>不是来自原始的,而是我们在\fff内容末尾添加的。有很多方法可以摆脱它,但我不知道解析循环是否应该是可扩展的(到目前为止,它是可扩展的,它可以在 中使用\edef,如果\par是 let to\relax或前缀,\noexpand以避免在 LaTeX 文档中根据位置具有特殊含义),所以我暂时保留它。

例如,如果\fff设置为包含整个文件,则这里是输出。

在此处输入图片描述

最后这<SPACE>不是来自文件内容而是来自我们的宏。

备注:“ParsePerWord” 有点误导,因为“words” 可能包含行尾。为了更接近文本编辑器对单词的称呼,我们首先应该使用分隔符而不是空格来表示“ParsePerLine” ^^J

相关内容