如何在宏中正确使用 \DeclareOption

如何在宏中正确使用 \DeclareOption

使用\ifthenelse语句我定义了一个宏,只要它与上次使用时的值不同,它就会打印它的值。

\RequirePackage{xifthen}
\def\storedval{} % create a macro to later store a value in
\newcommand{\mycommand}[1]{%
\ifthenelse{\isempty{#1}{}}{\\}{% If empty, don't print anything but keep an empty line.
\ifthenelse{\equal{#1}{\storedval}}{\\}% If value is the same as the previous one, don't print it but keep an empty line. 
{#1\\}\def\storedval{#1}}} % Else: print value and store it in \storedval

这样做的目的是,我获取另一个程序生成的数据,但如果重复,我不想打印该数据。在文档中,这:

\mycommand{A}
\mycommand{A}
\mycommand{A}
\mycommand{}
\mycommand{B}
\mycommand{C}
\mycommand{C}
\mycommand{A}

... 给我 A、三行空行、B、C、一行空行和 A。这就是我想要的。

现在我想将其存储在一个包中,并定义一个选项,让我选择是否要打印重复的行。我不知道如何\DeclareOption正确使用。我当然可以重复整个代码,并将其放在两个\DeclareOption语句中。但我认为有一种更经济的方法。

因此,我尝试了以下 MWE,但这显然是错误的方法(注释掉不起作用的行)。(免责声明:这是我第一次尝试为包声明选项...)

\documentclass{article} 
\usepackage{filecontents}
\begin{filecontents}{mypackage.sty}
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{mypackage}

\RequirePackage{xifthen}
\def\storedval{} % create a macro to later store a value in
\newcommand{\mycommand}[1]{%
\ifthenelse{\isempty{#1}{}}{\\}{% If empty, don't print anything but keep an empty line.
%\DeclareOption{skiprepetitions}{\ifthenelse{\equal{#1}{\storedval}}{\\}}% If value is the same as the previous one, don't print it but keep an empty line. 
%\DeclareOption{keeprepetitions}{} % don't do anything if this is selected
{#1\\}\def\storedval{#1}}} % Else: print value and store it in \storedval

\DeclareOption*{\PackageWarning{mypackage}{Unknown ‘\CurrentOption’}}
\ProcessOptions\relax
\end{filecontents}

\usepackage{mypackage}
%\usepackage[skiprepetitions]{mypackage}

\begin{document}
Testing:\\
\mycommand{A}
\mycommand{A}
\mycommand{A}
\mycommand{}
\mycommand{B}
\mycommand{C}
\mycommand{C}
\mycommand{A}
\mycommand{A}
\end{document}

答案1

这是一个功能齐全的包,可以满足您的需求。它使用expl3相关包,并且有三种使用命令的方式:您可以全局指定包选项、在本地使用设置命令或将可选参数传递给其中一个宏。

请注意,示例中的第二个 A 是通过传递可选的宏参数产生的。

example

\documentclass{article} 
\usepackage{filecontents}
\begin{filecontents}{mypackage.sty}
\RequirePackage{xparse} % enable LaTeX3 interfaces
\ProvidesExplPackage{mypackage}{2018-09-05}{0.1.0}{Data processing}

\RequirePackage{l3keys2e}
\keys_define:nn { jan } % define keys for module `jan`
    {
        skiprepetitions   .bool_set:N  = \l__jan_skiprep_bool, % define a boolean switch which is saved into a local variable
        skiprepetitions   .initial:n   = true, % set the value that is used when nothing is defined
        skiprepetitions   .default:n   = true, % set the value to use if you only pass `skiprepetitions` and no `=…`
        keeprepetitions   .bool_set_inverse:N = \l__jan_skiprep_bool,
        keeprepetitions   .default:n          = true
    }
\ProcessKeysOptions { jan } % make sure package options are processed

\NewDocumentCommand { \datasetup } { m } % define a command that locally sets the keys (as underscores are not allowed in normal LaTeX commands)
    {
        \keys_set:nn { jan } { #1 }
    }

\tl_new:N \g_jan_storedval_tl % create a new auxiliary variable to hold the last value

\prg_generate_conditional_variant:Nnn \tl_if_eq:nn { nV } { T, F, TF } % make \tl_if_eq semantically (and expansion-wise) better for our use-case
\NewDocumentCommand { \mycommand } { O{} m } % this is the main command with the first optional argument being empty if omitted and the second argument being mandatory
    {
        \group_begin: % start a group to make key changes local
        \keys_set:nn { jan } { #1 } % locally set keys
        \tl_if_empty:nTF { #2 } { \\ } % test if mandatory argument empty
            {
                \tl_if_eq:nVTF { #2 } \g_jan_storedval_tl % test if the mandatory argument equals the last value
                    {
                        \bool_if:NF \l__jan_skiprep_bool { #2 } % only output the mandatory argument if we are not in skip-mode
                    } { #2 }
                \\
                \tl_gset:Nn \g_jan_storedval_tl { #2 }
            }
        \group_end:
    }
\end{filecontents}

\usepackage{mypackage}

\begin{document}
Testing:\\
\mycommand{A}
\mycommand[keeprepetitions]{A}
\mycommand{A}
\mycommand{}
\mycommand{B}
\mycommand{C}
\mycommand{C}
\mycommand{A}
\mycommand{A}
\end{document}

答案2

参照你的问题标题,我认为不能\DeclareOption在宏中使用(正确)。对于宏,你需要使用由pgfkeyshttps://www.ctan.org/pkg/pgfkeys) 或类似的包。

但是从您的实际问题中,我推断您正在创建一个定义相应宏的包,并且您想要向包添加一个选项,该选项可以在加载时提供。在这种情况下\DeclareOption是正确的做法。
但不是您这样做的方式。您希望在调用\DeclareOption命令之前执行命令\ProcessOptions。因此,您希望它们在加载包时立即执行,因此它们不能在宏定义中使用(除了可能\edef但我们不要讨论这个)。

解决方法是创建一个新的布尔标志,如果使用该选项,其值将会改变。在我的示例中,我使用了以下etoolbox包:

\RequirePackage{etoolbox}

\newbool{@skiprepetitions}

\DeclareOption{skiprepetitions}{%
    % switch the bool-flag if this option is set
    \setbool{@skiprepetitions}{true}%
}

\ProcessOptions\relax

\newcommand{\myCommand}{%
    \ifthenelse{\isEmpty{#1}{}}{
        % if empty
        \ifbool{@skiprepetitions}{%
            % skip repetitions
        }{%
            % don't care about repetitions
        }%
    }{%
        % if not empty
    }%
}

答案3

定义宏并让选项决定使用哪一个。

\RequirePackage{filecontents}
\begin{filecontents}{mypackage.sty}
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{mypackage}

\DeclareOption{skiprepetitions}{%
  \AtBeginDocument{\let\mypackage@print\mypackage@print@skip}%
}
\DeclareOption{keeprepetitions}{%
  \AtBeginDocument{\let\mypackage@print\mypackage@print@keep}%
}
\ExecuteOptions{keeprepetitions}
\ProcessOptions\relax

\RequirePackage{xifthen}

\def\mypackage@storedval{} % create a macro to later store a value in
\newcommand{\mycommand}[1]{%
  \ifthenelse{\isempty{#1}}
    {% if empty just print an empty line
     \mbox{}\\%
    }
    {% if not empty
     \mypackage@print{#1}%
     \def\mypackage@storedval{#1}%
    }%
}

\def\mypackage@print@skip#1{%
  \ifthenelse{\equal{#1}{\mypackage@storedval}}
   {\mbox{}}
   {#1}%
  \\%
}
\def\mypackage@print@keep#1{#1\\}

\end{filecontents}

\documentclass{article} 

%\usepackage{mypackage}
\usepackage[skiprepetitions]{mypackage}

\begin{document}
Testing:\\
\mycommand{A}
\mycommand{A}
\mycommand{A}
\mycommand{}
\mycommand{B}
\mycommand{C}
\mycommand{C}
\mycommand{A}
\mycommand{A}
\mbox{}

\end{document}

相关内容