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
。