我怎样才能将整个文件内容逐字逐句地读入(expl3)字符串变量中?

我怎样才能将整个文件内容逐字逐句地读入(expl3)字符串变量中?

问题描述

如标题所示。

梅威瑟:

\documentclass{article}
\begin{document}

% first write some file content for demo...
\begin{filecontents*}{test test.txt}
line 1  !?#\xyz
line 2
\end{filecontents*}

% what to do here? I want to read the whole content of the file into variable \result

\ExplSyntaxOn
\str_show:N \result  % → the whole content of the file.
\ExplSyntaxOff

\end{document}

答案1

一种选择是使用\file_get:nnN。还有其他选择。

%! TEX program = pdflatex
\documentclass{article}
\begin{document}

\begin{filecontents*}{test test.txt}
line 1  !?#\xyz
line 2
\end{filecontents*}


\ExplSyntaxOn

\file_get:nnN {test~test.txt} {
    % alternatively (although the effects the different on LuaTeX)
    %   \int_step_inline:nnn {0} {255} {\char_set_catcode_other:n{#1}}
    \cctab_select:N \c_other_cctab
    \endlinechar=10~
    % ↑ this must be done after the cctab line
    %   because cctab changes the value of endlinechar as well
} \result
\str_set:NV \result \result

\str_show:N \result  % → the whole content of the file.
\ExplSyntaxOff

\end{document}

这会将文件的整个内容保存到变量中\result,文件中的每个“换行符”将用字符 10 表示。

解释

\file_get:nnN {test~test.txt} {

使用命令,如解释所示。请注意,由于这是 expl3 环境,因此空格需要写为~

    \cctab_select:N \c_other_cctab

设置 catcode。在 XeTeX 上,为 0..1114111 中的所有字符设置 catcode 是不切实际的,因此存在文件中的一个字符的 catcode 为 1/2 的极端情况,这会导致内容不平衡,从而导致错误。

请注意,此命令除了设置类别代码表正如其名称所暗示的那样,它还设置了行尾字符(在此 catcode 表中,endlinechar = -1),因此我们希望使用 charcode 为 10 的 char 来分隔行,我们需要在下面明确设置它。

    \endlinechar=10~

将 endlinechar 设置为 10,这样文件中的每个新行字符将用字符 10 来表示,准确地说,在结果字符串中是一个字符代码为 10 且 catcode 为 12 的标记。

这是 expl3 环境,明确指定空格来终止数字是一种很好的做法(或者使用\scan_stop:/ \relax,但我不喜欢这个名字,它更长。还有,\int_set:Nn \endlinechar {10}但是那......依赖于实施细节......?)

} \result
\str_set:NV \result \result

对结果进行去标记化。这一步很重要,因为为了将结果作为字符串获取,字符代码为 32(空格)的标记应具有 catcode 10(空格),而其 catcode 应为 12(其他),如上所述。

限制

  • 首先(仅适用于 XeTeX/LuaTeX 引擎),如果碰巧有某些字符的字符代码≥256 和一些不寻常的 catcode(例如 catcode 1 -- 开括号),它可能会中断。不过,大多数情况下,去标记化可以处理它。
  • 如果要读取的文件是 TeX 文件,则该文件上的 synctex 数据可能会“丢失”。 (细节很复杂。)
  • 每行尾随的空格都被删除(也可能包括尾随的制表符)。

相关问题

答案2

我建议使用\ior_str_map_variable:NNn

\begin{filecontents*}{test.txt}
line 1  !?#\xyz
line 2
\end{filecontents*}

\documentclass{article}

\ExplSyntaxOn
\ior_new:N \g__my_ior
\str_new:N \l__my_str

\cs_new_protected:Npn \my_verb_read_into:Nn #1#2
  {
    \str_clear_new:N #1   % define #1 if necessary, then clear it

    \ior_open:Nn \g__my_ior {#2}
    \ior_str_map_variable:NNn \g__my_ior \l__my_str
      {
        % Precaution in case the LINE FEED char ^^J might be active
        \str_put_right:Nx #1 { \l__my_str \char_generate:nn { 10 } { 12 } }
      }
    \ior_close:N \g__my_ior
  }

\NewDocumentCommand \verbReadInto { m m }
  {
    \my_verb_read_into:Nn #1 {#2}
  }
\ExplSyntaxOff

\begin{document}

\verbReadInto{\result}{test.txt}
\show\result

\end{document}

这表明:

\result=macro:
->line 1  !?#\xyz
line 2
.

所有行(包括最后一行)均以换行符 (10) 结束,类别代码为 12。

当然,可以使用和\g_tmpa_ior(并省去和 的声明),但当代码随着使用相同临时变量的新功能而增长时,要小心不要搬起石头砸自己的脚。\l_tmpa_str\my_verb_read_into:Nn\g__my_ior\l__my_str

实际上,如果不是因为代码块空间太小,我会将大部分函数名称都包含在这两个变量的名称中,原因是一样的。

相关内容