如何提取宏的定义,例如写入文件

如何提取宏的定义,例如写入文件

我想提取 LaTeX3 字符串中的宏定义(最好通过任何命令定义),例如稍后将其写入文件中。可以吗?

梅威瑟:

\documentclass[]{article}



\begin{document}

{
  \NewDocumentCommand{\Hello}{O{}m}{Hello #2 (arg #1).}
  Normal usage: \Hello[hey]{Alice}
  %% This part: put the code used to define the macro in a LaTeX3 string
  %% (I usually can't change how \Hello is defined, so I should only do something here)
  \ExplSyntaxOn
  \cs_generate_variant:Nn \str_replace_all:Nnn { Nnx }
  \cs_set:Nn \my_set_hash_robust:Nn {
    \str_set:Nn {#1} {#2}
    \str_replace_all:Nnx {#1} { ## } { \c_hash_str }
  }
  \cs_generate_variant:Nn \my_set_hash_robust:Nn { cn }
  \cs_generate_variant:Nn \my_set_hash_robust:Nn { cx }

  %% This line should be replaced by an automatic code somehow
  \my_set_hash_robust:Nn \l_contentHello_str {\NewDocumentCommand{\Hello}{O{}m}{Hello ~#2~ (arg~ #1).}}
  %%% This part should not really be touched
  \ior_new:N \g_myfile
  \iow_open:Nn \g_myfile {cmd.tex}
  \cs_generate_variant:Nn \iow_now:Nn { NV }
  \iow_now:NV \g_myfile {\l_contentHello_str}
  \iow_close:N \g_myfile
  \ExplSyntaxOff
}

\input{cmd.tex}
\Hello[my args]{Bob}

\end{document}

编辑 我们正在取得进展,看这里如何提取用户在 \NewDocumentCommand 中输入的文本

答案1

因此,感谢 egreg 的指针另一个答案,我设法让它工作:

在此处输入图片描述

\documentclass{article}
\usepackage{xparse}

\makeatletter
\ExplSyntaxOn
\cs_generate_variant:Nn \cs_replacement_spec:N { c }
\cs_generate_variant:Nn \cs_argument_spec:N { c }

\cs_new:Nn \__myModule_getCommandDefinitionFromXparse:N
{
  \str_clear_new:N \l__myModule_definition_str
  \GetDocumentCommandArgSpec { #1 }
  \str_set:Nx \l__myModule_definition_str {
    \c_backslash_str DeclareDocumentCommand
    \c_left_brace_str
    \c_backslash_str \cs_to_str:N #1
    \c_right_brace_str
    \c_left_brace_str \ArgumentSpecification \c_right_brace_str
    \c_left_brace_str
    \cs_replacement_spec:c { \cs_to_str:N #1 ~ code }
    \c_right_brace_str
  }%
}

\cs_new:Nn \__myModule_getCommandDefinitionFromDef:N
{
  \str_clear_new:N \l__myModule_definition_str
  \str_set:Nx \l__myModule_definition_str {
    \c_backslash_str def \c_backslash_str \cs_to_str:N #1
    \cs_argument_spec:c { \cs_to_str:N #1 }
    \c_left_brace_str
    \cs_replacement_spec:c { \cs_to_str:N #1 }
    \c_right_brace_str
  }%
}

\def\myModule@extractDefaultNewcommand#1#2#3#4{
  #4%
}%

\cs_new:Nn \__myModule_getCommandDefinitionFromNewcommand:N
{
  \str_clear_new:N \l__myModule_definition_str
  \str_clear_new:N \l_myModule_tmp
  %% \l_myModule_tmp will look like [#1]#2#3#4#5#6#7:
  \str_set:Nx \l_myModule_tmp {\cs_argument_spec:c { \c_backslash_str \cs_to_str:N #1 }}%
  %% We remove the brackets:
  \str_replace_all:Nnn \l_myModule_tmp {[} {}
  \str_replace_all:Nnn \l_myModule_tmp {]} {}
  \str_set:Nx \l__myModule_definition_str {
    %% this line will be like "\newdocumentcommand{\mymacro}"
    \c_backslash_str newcommand \c_left_brace_str \c_backslash_str \cs_to_str:N #1 \c_right_brace_str
    %% It must have at least one argument, since elements without optional arguments are turned into \def
    %% Moreover, macros can't have more than 1 argument, so it will be easier to parse, we just need the last digit
    [\str_range:Nnn \l_myModule_tmp {-1} {-1}] %% <- this is the number of mandatory arguments
    [\expandafter \myModule@extractDefaultNewcommand #1 ] %% <- this is the value of the default argument
    \c_left_brace_str
    \cs_replacement_spec:c { \c_backslash_str \cs_to_str:N #1 }
    \c_right_brace_str
  }%
}

\NewDocumentCommand{\myModuleGetCommandDefinition}{m}{
  \cs_if_exist:NTF #1 {
    \cs_if_exist:cTF {\cs_to_str:N #1 ~ code}{
      % xparse-based definition
      \__myModule_getCommandDefinitionFromXparse:N #1%
      \l__myModule_definition_str%
    } {
      \cs_if_exist:cTF {\c_backslash_str \cs_to_str:N #1}{
        % \newcommand-based definition
        \__myModule_getCommandDefinitionFromNewcommand:N #1
        \l__myModule_definition_str%
      }{
        % \def-based definition
        \__myModule_getCommandDefinitionFromDef:N #1
        \l__myModule_definition_str%
      }
    }
  }{
    \PackageError{myModule}{The~macro~#1~does~not~exist}
  }
}

\ExplSyntaxOff
\makeatother

\begin{document}

This works for xparse-based definitions:

\NewDocumentCommand{\testXparse}{O{default}m}{Hey (#1) #2 you are nice.}
\texttt{\myModuleGetCommandDefinition{\testXparse}}\\

This works for simple def:

\def\testDef[#1]#2{I am #1 from #2 in a def.}
\texttt{\myModuleGetCommandDefinition{\testDef}}\\

This works now for simple newcommand-based definitions:

\newcommand{\testNewcommand}[7][mydefaultvalue]{From newcommand (#1) #2 seems to work.}
\texttt{\myModuleGetCommandDefinition{\testNewcommand}}\\

If we do not put any default value, it is equivalent to a def:\\
\newcommand{\testNewcommandNoDefault}[2]{From newcommand (#1) #2 seems to work.}
\texttt{\myModuleGetCommandDefinition{\testNewcommandNoDefault}}

Test without optional argument:

\newcommand{\testNewcommandNoOpt}[7]{From newcommand (#1) #2 without optional arguments.}
\texttt{\myModuleGetCommandDefinition{\testNewcommandNoOpt}}\\

\end{document}

相关内容