我正在寻找一个可以让我编写以下命令的包:
\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
(为清楚起见添加了空格,但它们会被忽略)。