部分扩展:仅此而已

部分扩展:仅此而已

我正在寻找一个可以让我编写以下命令的包:

\tofile{filename}{One}{Two} FROM HERE
  here is some nonsensical list of commands,
  \unexpand\expandafter\gdef\indlude{#1}\def\expand\myOtherCrazyMacro
  but who cares, I can even place my C code here
  #include <stdio.h>
  main() {
    printf("#2",\n);
  }
  this }}{{is some other illegal LaTeX code, which uses % percents, 
  & other _^^^_ ASCII stuff. 
TO THERE

这样“FROM HERE”到“TO THERE”之间的所有内容都会出现在文件名中,但“#1”和“#2”除外,因为它们会被宏参数替换。

我自己的bashful包做了一些非常相似的事情,所以我想我可以以某种方式破解它,但我希望找到一个现成的解决方案,或者比我在我的包中所做的悲惨破解更体面的东西。

运行此宏之后,该文件的内容filename应为:

  here is some nonsensical list of commands,
  \unexpand\expandafter\gdef\indlude{One}\def\expand\myOtherCrazyMacro
  but who cares, I can even place my C code here
  #include <stdio.h>
  main() {
    printf("Two",\n);
  }
  this }}{{is some other illegal LaTeX code, which uses % percents, 
  & other _^^^_ ASCII stuff. 

答案1

使用#双重含义在标准方法中是不可能的。下面这个方法似乎可行:

\documentclass{article}
\makeatletter
\newwrite\tofile@write
\def\tofile#1#2#3FROMHERE
 {%
  \begingroup
  \immediate\openout\tofile@write=#1\relax
  \let\do\@makeother\dospecials
  \endlinechar=`\^^J
  \@tofile{#2}{#3}%
 }
\def\TOTHERE{TOTHERE}
\def\@tofile#1#2#3^^J{%
  \def\@test{#3}%
  \ifx\@test\TOTHERE
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {\endgroup}%
  {\toks@{#3}%
   \begingroup\catcode`\#=6 \endlinechar=\m@ne
   \everyeof{\noexpand}%
   \xdef\@temp##1##2{\scantokens\expandafter{\the\toks@}}%
   \endgroup
   \immediate\write\tofile@write{\@temp{#1}{#2}}%
   \@tofile{#1}{#2}}%
}
\makeatother

\begin{document}

\tofile{filename}{One}{Two}FROMHERE
Something \absurd{||-\for\yossi
Else #1 or #2
TOTHERE

\end{document}

生成的文件是

Something \absurd{||-\for\yossi
Else One or Two

另一个解决方案是使用 LaTeX3 功能。开始字符串应等于结束字符串,并且不与第二个参数分开;仅使用可打印和非 (TeX) 特殊 ASCII 字符。示例中使用的第一个参数只是为了\jobname.txt不破坏我的文件系统中的其他文件,您可以使用任何您想要的名称。

可以容纳更多替换,请告诉我。

\documentclass{article}
\usepackage{xparse,l3regex}

\ExplSyntaxOn
\NewDocumentCommand{\tofile}{m}
 {
  \yossi_tofile:n { #1 }
 }

\iow_new:N \g_yossi_tofile_write_stream

\cs_new_protected:Npn \yossi_tofile:n #1
 {
  \group_begin:
  \tex_endlinechar:D `\^^J
  \iow_open:Nn \g_yossi_tofile_write_stream { #1 }
  \yossi_tofile_aux:nnw
 }

\cs_new_protected:Npn \yossi_tofile_aux:nnw #1 #2 #3 ~%
 {
  \tl_set:Nn \l_yossi_eof_tl { #3 }
  \tl_trim_spaces:N \l_yossi_eof_tl
  \cs_set_eq:NN \do \char_set_catcode_other:N
  \dospecials
  \yossi_readline:nnw { #1 } { #2 }
 }

\cs_new_protected:Npn \yossi_readline:nnw #1 #2 #3 ^^J
 {
  \str_if_eq:VnTF \l_yossi_eof_tl { #3 }
   {
    \iow_close:N \g_yossi_tofile_write_stream
    \group_end:
   }
   {
    \yossi_replace_write:nnn { #1 } { #2 } { #3 }
    \yossi_readline:nnw { #1 } { #2 }
   }
 }

\cs_new_protected:Npn \yossi_replace_write:nnn #1 #2 #3
 {
  \tl_set:Nn \l_tmpa_tl { #3 }
  \regex_replace_all:nnN { \#1 } { #1 } \l_tmpa_tl
  \regex_replace_all:nnN { \#2 } { #2 } \l_tmpa_tl
  \iow_now:NV \g_yossi_tofile_write_stream \l_tmpa_tl
 }

\cs_generate_variant:Nn \iow_now:Nn { NV }
\cs_generate_variant:Nn \str_if_eq:nnTF { V }

\ExplSyntaxOff

\begin{document}

\tofile{\jobname.txt}{One}{Two}<<EOF
here is some nonsensical list of commands,
\unexpand\expandafter\gdef\indlude{#1}\def\expand\myOtherCrazyMacro
but who cares, I can even place my C code here
#include <stdio.h>
main() {
  printf("#2",\n);
}
this }}{{is some other illegal LaTeX code, which uses % percents, 
& other _^^^_ ASCII stuff. 
<<EOF

\end{document}

这是写出的文件:

here is some nonsensical list of commands,
\unexpand\expandafter\gdef\indlude{One}\def\expand\myOtherCrazyMacro
but who cares, I can even place my C code here
#include <stdio.h>
main() {
  printf("Two",\n);
}
this }}{{is some other illegal LaTeX code, which uses % percents,
& other _^^^_ ASCII stuff.

感谢 Joseph Wright 通过正则表达式建议替换。


新版本,允许任意数量的参数;但是必须以不同的方式指定它们,请参阅示例代码。

\documentclass{article}
\usepackage{xparse,l3regex}

\ExplSyntaxOn
\NewDocumentCommand{\tofile}{m}
 {
  \manual_tofile:n { #1 }
 }

\iow_new:N \g_manual_tofile_write_stream
\tl_const:Nn \c_manual_specials_tl { \  \\ \{ \} \$ \& \# \^ \_ \% \~ }
\tl_new:N \l_manual_argument_tl
\tl_new:N \l_manual_line_tl
\seq_new:N \l_manual_arguments_seq
\int_new:N \l_manual_arguments_int

\cs_new_protected:Npn \manual_dospecials:
 {
  \tl_map_inline:Nn \c_manual_specials_tl
   {
    \char_set_catcode_other:N ##1
   }
 }

\cs_new_protected:Npn \manual_tofile:n #1
 {
  \group_begin:
  \tex_endlinechar:D `\^^J
  \iow_open:Nn \g_manual_tofile_write_stream { #1 }
  \manual_tofile_aux:nw
 }

\cs_new_protected:Npn \manual_tofile_aux:nw #1 #2 ~%
 {% #1 is the list of arguments, #2 is the terminator
  \tl_set:Nn \l_manual_eof_tl { #2 }
  \tl_trim_spaces:N \l_manual_eof_tl
  \seq_set_split:Nnn \l_manual_arguments_seq { } { #1 }
  \int_set:Nn \l_manual_arguments_int { \seq_count:N \l_manual_arguments_seq }
  \manual_dospecials:
  \manual_readline:w
 }

\cs_new_protected:Npn \manual_readline:w #1 ^^J
 {
  \str_if_eq:VnTF \l_manual_eof_tl { #1 }
   {
    \iow_close:N \g_manual_tofile_write_stream
    \group_end:
   }
   {
    \manual_replace_write:n { #1 }
    \manual_readline:w
   }
 }

\cs_new_protected:Npn \manual_replace_write:n #1
 {
  \tl_set:Nn \l_manual_line_tl { #1 }
  \int_step_inline:nnnn { 1 } { 1 } { \l_manual_arguments_int }
   {
    \tl_set:Nx \l_manual_argument_tl { \seq_item:Nn \l_manual_arguments_seq { ##1 } }
    \regex_replace_all:nnN { \# ##1 } { \u{l_manual_argument_tl} } \l_manual_line_tl
   }
  \iow_now:NV \g_manual_tofile_write_stream \l_manual_line_tl
 }

\cs_generate_variant:Nn \iow_now:Nn { NV }
\cs_generate_variant:Nn \str_if_eq:nnTF { V }

\ExplSyntaxOff

\begin{document}
\tofile{test.c}{{One}{Two}{Three}}<<EOF
/* #1, #2 */
#include <stdio.h>
main() {
  printf("#3",\n);
}
<<EOF

\end{document}

\tofile{\jobname.txt}{{One}{Two}{ASCII}}<<EOF
here is some nonsensical list of commands,
\unexpand\expandafter\gdef\indlude{#1}\def\expand\myOtherCrazyMacro
but who cares, I can even place my C code here
#include <stdio.h>
main() {
  printf("#2",\n);
}
this }}{{is some other illegal LaTeX code, which uses % percents, 
& other _^^^_ #3 stuff. 
<<EOF

\end{document}

此处的参数有三个,在第二个参数中指定为括号内的项\tofile

\tofile{\jobname.txt}{ {One} {Two} {ASCII} }<<EOF

(为清楚起见添加了空格,但它们会被忽略)。

相关内容