在宏中将命令与参数连接起来?

在宏中将命令与参数连接起来?

我想从文本文件中读取几行,用“样式”包装\texttt每行,然后将其连接到我可以在文档中使用的宏。我想出了这个 MWE:

\documentclass{article}

\usepackage{filecontents} % tlmgr install filecontents

\begin{filecontents*}{test-2.txt}
some more
words in
here so as
to eventually
print
\end{filecontents*}

\usepackage{xstring}

\def\totcontent{}
\def\mystyle#1{\texttt{#1}}

% related: http://tex.stackexchange.com/questions/116078/expand-command-read-from-file
\newread\myread
\makeatletter
\immediate\openin\myread=test-2.txt
\@whilesw\unless\ifeof\myread\fi{%
  \readline\myread t\expandafter o\csname tmpline\endcsname %
  \typeout{Got tmpline: \tmpline} %
  \StrGobbleRight{\tmpline}{1}[\tmpline] % remove the ^^M newline (last 1 char)
  \ifx\tmpline\empty\else %
    %\edef\totcontent{\totcontent, \tmpline} % works without mystyle
    %\edef\totcontent{\totcontent, \mystyle{\tmpline}} % fail, breaks
    % via http://tex.stackexchange.com/a/74709/2595:
    \g@addto@macro\totcontent{, \mystyle{\tmpline}} % compiles, but no content in output
  \fi %
}
\immediate\closein\myread
\makeatother


\begin{document}

\typeout{totcontent is: \totcontent.}

I got this: \totcontent.

\end{document}

在所有情况下,我都会得到以下文件读数:

Got tmpline: some more^^M
Got tmpline: words in^^M
Got tmpline: here so as^^M
Got tmpline: to eventually^^M
Got tmpline: print^^M
Got tmpline: ^^M

xstring...这意味着行结尾被保留,所以我用's删除“字符串”末尾的字符\StrGobbleRight

第一种情况,\edef\totcontent{\totcontent, \tmpline}工作正常,但没有样式——然后输入内容显示:

totcontent is: , some more, words in, here so as, to eventually, print.

第二种情况,,\edef\totcontent{\totcontent, \mystyle{\tmpline}}完全失效:

! Argument of \@xs@StrGobbleRight has an extra }.
<inserted text> 
                \par 
l.30 }

在这里我打算将\mystyle其用作占位符宏 - 期望它在连接中\edef会向下扩展为\texttt标记,我记得这些标记是\protected,因此不会进一步扩展。显然,这没有奏效。

第三种情况,\g@addto@macro\totcontent{, \mystyle{\tmpline}}实际上可以编译,但是给出的结果为:

totcontent is: , \texttt {}, \texttt {}, \texttt {}, \texttt {}, \texttt {}.

...这很接近,但仍然不是我想要的(我希望\texttt由循环中的相应参数填充)。

那么,我该如何进行连接呢?最后我得到的结果如下:

totcontent is: , \texttt {some more}, \texttt {words in}, \texttt {here so as}, \texttt {to eventually}, \texttt {print}.

...这样它的排版也会如我们期望的那样吗?


As per comments, example with `\read`:

\documentclass{article}

\usepackage{filecontents} % tlmgr install filecontents

\begin{filecontents*}{test-2.txt}
some more
words in
here so as
to eventually
print
\end{filecontents*}

\def\totcontent{}
\def\mystyle#1{\texttt{#1}}

\newread\myread
\makeatletter
\immediate\openin\myread=test-2.txt
\@whilesw\unless\ifeof\myread\fi{%
  \read\myread to \tmpline %
  \typeout{Got tmpline: \tmpline} %
%   \ifx\tmpline\empty\else %
  \ifx\tmpline\par\else %
    %\edef\totcontent{\totcontent, \tmpline} % works without mystyle
    %\edef\totcontent{\totcontent, \mystyle{\tmpline}} % fail, breaks
    \g@addto@macro\totcontent{, \mystyle{\tmpline}} % compiles, but no content in output
  \fi %
}
\immediate\closein\myread
\makeatother


\begin{document}

\typeout{totcontent is: \totcontent.}

I got this: \totcontent.

\end{document}

印刷:

Got tmpline: some more 
Got tmpline: words in 
Got tmpline: here so as 
Got tmpline: to eventually 
Got tmpline: print 
Got tmpline: \par 

然后\edef\totcontent{\totcontent, \mystyle{\tmpline}}失败了:

! Use of \@pr@videpackage doesn't match its definition.

\g@addto@macro\totcontent{, \mystyle{\tmpline}}产生:

totcontent is: , \texttt {\par }, \texttt {\par }, \texttt {\par }, \texttt {\par }, \texttt {\par }, \texttt {\par }.

...这仍然不是我想要的...

答案1

常见的问题是行尾。您想要\readline,但正常\read

\begin{filecontents*}{\jobname.txt}
some more
words in
here so as
to eventually
print
\end{filecontents*}

\documentclass{article}

\makeatletter
\newread\myread
\makeatletter
\def\strip@final@space{\expandafter\strip@final@sp@ce\@tempa\strip@final@sp@ce}
\def\strip@final@sp@ce#1 \strip@final@sp@ce{\def\@tempa{#1}}
\def\a@par{\par}
\toks@={}
\openin\myread=\jobname.txt
\@whilesw\unless\ifeof\myread\fi{%
  \read\myread to \@tempa
  \typeout{Got tmpline: \@tempa}%
  \ifx\@tempa\a@par
  \else
    \strip@final@space
    \toks@=\expandafter{\the\expandafter\toks@\expandafter\texttt\expandafter{\@tempa}, }%
  \fi
}
\edef\totcontent{\the\toks@}
\closein\myread
\makeatother


\begin{document}

\typeout{totcontent is: \totcontent.}

I got this: \totcontent.

\end{document}

这是日志文件中的输出

totcontent is: \texttt {some more}, \texttt {words in}, \texttt {here so as}, \
texttt {to eventually}, \texttt {print}, .

请注意\@tempa永远不会为空;空行或最后一个空行将使\@tempa扩展为\par

一种更简单的方法expl3

\begin{filecontents*}{\jobname.txt}
some more
words in
here so as
to eventually
print
\end{filecontents*}

\documentclass{article}
\usepackage{expl3}

\ExplSyntaxOn
\seq_new:N \l_sdaau_lines_seq
\tl_new:N \l_sdaau_totcontent_tl
\ior_new:N \sdaau_read_stream
\ior_open:Nn \sdaau_read_stream { \c_job_name_tl.txt }
\ior_map_inline:Nn \sdaau_read_stream
 {
  %\msg_term:n {Got~line:~|#1|} % uncomment for debugging
  \seq_put_right:Nn \l_sdaau_lines_seq { \texttt { #1 } }
 }
\tl_set:Nx \l_sdaau_totcontent_tl { \seq_use:Nn \l_sdaau_lines_seq { ,~ } }

\tl_set_eq:NN \totcontent \l_sdaau_totcontent_tl
\ExplSyntaxOff

\begin{document}

\typeout{totcontent is: \totcontent.}

I got this: \totcontent.

\end{document}

输出为

totcontent is: \texttt {somemore}, \texttt {wordsin}, \texttt {heresoas}, \text
tt {toeventually}, \texttt {print}.

请注意,没有尾随逗号。

如果您计划在文件中留空行,则将行

  \seq_put_right:Nn \l_sdaau_lines_seq { \texttt { #1 } }

进入

  \tl_if_blank:nF { #1 }
   {
    \seq_put_right:Nn \l_sdaau_lines_seq { \texttt { #1 } }
   }

答案2

您可以\addto通过以下方式使用宏:

\long\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
\def\addtolist#1{\global\addto\totcontent{, \texttt{#1}}}

\newread\infile
\openin\infile=test-2.txt
\bgroup
  \endlinechar=-1 \gdef\totcontent{}%
  \loop
    \unless\ifeof\infile
       \read\infile to\tmp
       \ifx\tmp\empty \else \expandafter\addtolist\expandafter{\tmp}\fi
       \repeat
\egroup

\message{totcontent is: \meaning\totcontent}

终端打印:

totcontent is: macro:->, \texttt {some more}, \texttt {words in}, \texttt {here
 so as}, \texttt {to eventually}, \texttt {print} 

答案3

好的,我至少得到了一个可行的版本 - 虽然我不能说我明白发生了什么;所以更博学的答案仍然会受到欢迎。但经过一番折腾之后,我得到了一个“两步”方法,通过调用来\protected@edef工作。这是 MWE:

\documentclass{article}

\usepackage{filecontents} % tlmgr install filecontents

\begin{filecontents*}{test-2.txt}
some more
words in
here so as
to eventually
print
\end{filecontents*}

\def\totcontent{}
\def\mystyle#1{\texttt{#1}}

\def\tst{\texttt{something here}, \texttt{and else}}

\newread\myread
\makeatletter
\immediate\openin\myread=test-2.txt
\@whilesw\unless\ifeof\myread\fi{%
  \read\myread to \tmpline %
  \typeout{Got tmpline: \tmpline} %
  %\ifx\tmpline\par % does NOT work if \tmpline is \par!
  \if\tmpline\par % does work if \tmpline is \par!
    \typeout{PAR} %
  \else %
    %\edef\mytmp{\par} \typeout{1: -\mytmp-}      % dbg
    %\edef\mytmp{\tmpline} \typeout{2: -\mytmp-}  % dbg
    \protected@edef\mytmp{\mystyle{\tmpline}} %
    \typeout{mytmp: \mytmp} %
    \protected@edef\totcontent{\totcontent, \mytmp}
  \fi %
}
\immediate\closein\myread
\makeatother


\begin{document}

\typeout{totcontent is: \totcontent.}

I had this: \tst;

I got this: \totcontent.

\end{document}

这会在终端打印输出中产生:

Got tmpline: some more 
mytmp: \texttt {some more }
Got tmpline: words in 
mytmp: \texttt {words in }
Got tmpline: here so as 
mytmp: \texttt {here so as }
Got tmpline: to eventually 
mytmp: \texttt {to eventually }
Got tmpline: print 
mytmp: \texttt {print }
Got tmpline: \par 
PAR

totcontent is: , \texttt {some more }, \texttt {words in }, \texttt {here so as
 }, \texttt {to eventually }, \texttt {print }.

... 并且\totcontent排版符合您的预期,具有正确的字体和所有内容;这正是我最初想要的。

相关内容