我如何让 (La)TeX(3) 逐个字符地读取文件?

我如何让 (La)TeX(3) 逐个字符地读取文件?

我正在做代码降临 (2022)在 LaTeX3 中(不,确实如此)。每个挑战都涉及一些输入,对于第 6 天来说,这些输入只有一行,而且很长(4096 个字符)。这一行需要逐个字符地处理,所以我想让 TeX 逐个字符地读取它。现在,我知道 TeX 可以轻松处理这种长度的标记列表,但我在 LaTeX3 中执行 AoC 的目的是为了更好地理解语言,而不是找到最有效或最有效的解决方案。因此,即使我最终没有使用逐个字符的方法,而是将整个文件读入单个标记列表,我仍然想知道如何做到这一点。

以下是我尝试过的:

\cs_set_eq:Nc \aoc_input: {@@input} % to get an expandable file input
\cs_new:Npn \aoc_process_char:w #1
{
  \tl_if_eq:nnF {#1} {\par} % this doesn't work
  {
    \aoc_process_char:w
  }
}

\exp_after:wN \aoc_process_char:w \aoc_input: file.txt\relax

这不起作用,因为\par文件末尾的\outer不能用作函数的参数。因此,在阅读此网站时,我看到了依次\let对每个标记执行某些操作并进行测试的建议,例如:

\def\dostuff{%
  \ifx\tmpvar\par
  \else
    \expandafter
    \slurptoken
  \fi
}
\def\slurptoken{\afterassignment\dostuff\let\tmpvar=}
\expandafter\slurptoken\@@input file.txt\relax

我正在努力将其转换为 LaTeX3 语法。感觉其中一种\peek_after:Nw函数应该是我正在寻找的,但我需要一个从流中吸收标记的函数,而remove名称中带有的函数只测试 charcode 或 catcode,而我希望能够使用该标记进行更多处理。

那么上述 TeX 代码的最佳 LaTeX3 等效代码是什么?

答案1

我认为最简单的方法是使用

\peek_analysis_map_inline:n { <inline code> }

此函数在输入流中向前查看,并将后面的标记提供给<inline code><inline code>接收三个参数:

  1. 某些东西o- 或 -x扩展到所见的标记;
  2. 标记的字符代码(如果是控制序列则为 -1);
  3. 令牌的类别代码(如果是控制序列则为 0),以十六进制表示。

有了这些信息,您就可以对输入进行任何所需的处理。

\peek_analysis_map_inline:n特别好,因为它会花一些时间来区分 a{和 a \bgroup,这并不简单(用通常的\futurelet方法是不可能的),而且它使得根据需要处理标记变得非常容易。

下面是一个示例。它从基础开始,检查文件是否存在。然后插入\tex_everyeof:D { \__loopspace_file_process_end: }一个标记来表示文件结束。然后输入文件,并用 进行处理\peek_analysis_map_inline:n

\ExplSyntaxOn
\NewDocumentCommand \processfile { m }
  { \loopspace_file_process:n {#1} }
\cs_new_protected:Npn \loopspace_file_process:n #1
  {
    \file_if_exist:nTF {#1}
      { \__loopspace_file_process:n {#1} }
      { \msg_error:nnn { loopspace } { file-not-found } {#1} }
  }
\msg_new:nnn { loopspace } { file-not-found } { File~'#1'~not~found. }
\cs_new_protected:Npn \__loopspace_file_process:n #1
  {
    \group_begin:
      \tex_everyeof:D { \__loopspace_file_process_end: }
      \exp_after:wN \__loopspace_file_process:w \tex_input:D {#1}
    \group_end:
  }
\cs_new_protected:Npn \__loopspace_file_process:w
  {
    \peek_analysis_map_inline:n
      {
        \int_compare:nNnT {##2} = { -1 }
          {
            \exp_after:wN \token_if_eq_meaning:NNT
                ##1 \__loopspace_file_process_end:
              { \peek_analysis_map_break: }
          }
        % process token:
        \mode_leave_vertical:
        \exp_after:wN \token_to_str:N ##1 ~ ( ##2 ,~ ##3 ) \par
        % --------------
      }
  }
\cs_new_protected:Npn \__loopspace_file_process_end:
  { \msg_error:nn { loopspace } { premature-end } }
\msg_new:nnn { loopspace } { premature-break }
  {
    Premature~usage~of~\iow_char:N\\peek_analysis_map_break:.\\
    Some~content~may~have~been~left~over.
   }
\ExplSyntaxOff

\documentclass{article}
\begin{filecontents}{tmp.tex}
Lorem ipsum \textbf{dolor sit amet}. \bgroup{}$&#^_
\end{filecontents}
\begin{document}
\ttfamily \processfile{tmp.tex}
\end{document}

相关内容