即时修改标签参考打印

即时修改标签参考打印

如果没有对最大工作示例进行简要描述(其中包括以下主要功能),这个问题就很难解释我正在写的一个包,因此在真正进入正题之前,我在下面加上了这段话:

% arara: lualatex
% arara: lualatex
\documentclass{article}
\usepackage{xparse}
\usepackage{expl3}
\usepackage{l3keys2e}
\usepackage{chngcntr}

\setlength\parindent{0pt}

\ExplSyntaxOn

\cs_new:Nn \__teachingtools_print_question: {
    \str_clear_new:N \l__teachingtools_question_str
    \str_put_left:Nn \l__teachingtools_question_str { Question }
    \bool_if:NT \l__teachingtools_numbered_question_bool {
        \refstepcounter{question}
        \str_put_right:Nn \l__teachingtools_question_str { ~ }
        \__teachingtools_print_question_label:
        \str_put_right:Nx \l__teachingtools_question_str { \l__teachingtools_question_label_str }
    }
    \str_put_right:Nx \l__teachingtools_question_str { \l__teachingtools_suffix_character_str }

    % Prints format string of label in terminal: how can I use this to change the
    % printing of \refl{qu:label}?
    % \tl_show:N \l__teachingtools_question_label_format_tl
    % It can be used as an argument to `\renewcommand\thequestion`, and appears to work, with the caveat that the redefinition is local to the group created by each environment instance.
    \renewcommand\thequestion{ \l__teachingtools_question_label_format_tl }

    \par \skip_vertical:N \l__teachingtools_questionbefore_skip
    \group_begin:
    \bfseries \l__teachingtools_question_str \par\nopagebreak
    \group_end:
}
\cs_new:Nn \__teachingtools_print_question_label: {
    \str_clear_new:N \l__teachingtools_question_label_str
    \tl_clear_new:N \l__teachingtools_question_label_format_tl
    \bool_if:NT \l__teachingtools_question_prefix_bool {
        \str_put_right:Nx \l__teachingtools_question_label_str { \l__teachingtools_question_prefix_tl }
        \str_put_right:Nx \l__teachingtools_question_label_str { \l__teachingtools_prefix_separator_str }
        \tl_put_right:NV \l__teachingtools_question_label_format_tl { \l__teachingtools_question_prefix_tl }
        \tl_put_right:NV \l__teachingtools_question_label_format_tl { \l__teachingtools_prefix_separator_str }
    }
    \str_put_right:Nx \l__teachingtools_question_label_str { \l__teachingtools_question_label_tl }
    \tl_put_right:NV \l__teachingtools_question_label_format_tl { \l__teachingtools_question_label_tl }
}
\newcounter{question}
\keys_define:nn { teachingtools / question } {
    reset .default:n = section,
    reset .choices:nn = {
        part, chapter, section, subsection, subsubsection, paragraph, subparagraph
    }
    {
        \counterwithin*{question}{ \tl_to_str:N \l_keys_choice_tl }
    },
    reset / none .code:n = {
        \counterwithout*{question}{section}
    },
}
\bool_new:N \l__teachingtools_numbered_question_bool
\keys_define:nn { teachingtools } {
    question / number .code:n = {
        \int_set_eq:NN \l_tmpa_int #1
        \int_decr:N \l_tmpa_int
        \setcounter{question}{ \int_use:N \l_tmpa_int }
    },
}
\str_new:N \l__teachingtools_prefix_separator_str
\keys_define:nn { teachingtools } {
    prefix-separator .choice:,
    prefix-separator / dash .code:n = {
        \str_set:Nn \l__teachingtools_prefix_separator_str { - }
    },
    prefix-separator / dot .code:n = {
        \str_set:Nn \l__teachingtools_prefix_separator_str { . }
    },
    prefix-separator / colon .code:n = {
        \str_set:Nx \l__teachingtools_prefix_separator_str { \c_colon_str }
    },
    prefix-separator / none .code:n = {
        \str_gclear:N \l__teachingtools_prefix_separator_str
    },
    prefix-separator .default:n = none,
    prefix-separator .initial:n = none,
}
\tl_new:N \l__teachingtools_question_prefix_tl
\bool_new:N \l__teachingtools_question_prefix_bool
\keys_define:nn { teachingtools / question } {
    prefix .choice:,
    prefix / part .code:n = {
        \tl_set:Nn \l__teachingtools_question_prefix_tl { \thepart }
        \keys_set:nn { teachingtools } {
            question / reset = part,
            prefix-separator = dash,
        }
        \bool_set_true:N \l__teachingtools_question_prefix_bool
    },
    prefix / chapter .code:n = {
        \tl_set:Nn \l__teachingtools_question_prefix_tl { \thechapter }
        \keys_set:nn { teachingtools } {
            question / reset = chapter,
            prefix-separator = dash,
        }
        \bool_set_true:N \l__teachingtools_question_prefix_bool
    },
    prefix / section .code:n = {
        \tl_set:Nn \l__teachingtools_question_prefix_tl { \thesection }
        \keys_set:nn { teachingtools } {
            question / reset = section,
            prefix-separator = dash,
        }
        \bool_set_true:N \l__teachingtools_question_prefix_bool
    },
    prefix / subsection .code:n = {
        \tl_set:Nn \l__teachingtools_question_prefix_tl { \thesubsection }
        \keys_set:nn { teachingtools } {
            question / reset = subsection,
            prefix-separator = dash,
        }
        \bool_set_true:N \l__teachingtools_question_prefix_bool
    },
    prefix / subsubsection .code:n = {
        \tl_set:Nn \l__teachingtools_question_prefix_tl { \thesubsubsection }
        \keys_set:nn { teachingtools } {
            question / reset = subsubsection,
            prefix-separator = dash,
        }
        \bool_set_true:N \l__teachingtools_question_prefix_bool
    },
    prefix / paragraph .code:n = {
        \tl_set:Nn \l__teachingtools_question_prefix_tl { \theparagraph }
        \keys_set:nn { teachingtools } {
            question / reset = paragraph,
            prefix-separator = dash,
        }
        \bool_set_true:N \l__teachingtools_question_prefix_bool
    },
    prefix / subparagraph .code:n = {
        \tl_set:Nn \l__teachingtools_question_prefix_tl { \thesubparagraph }
        \keys_set:nn { teachingtools } {
            question / reset = subparagraph,
            prefix-separator = dash,
        }
        \bool_set_true:N \l__teachingtools_question_prefix_bool
    },
    prefix / none .code:n = {
        \tl_gclear:N \l__teachingtools_question_prefix_tl
    },
    prefix .default:n = none,
    prefix .initial:n = none,
}
\tl_new:N \l__teachingtools_question_label_tl
\keys_define:nn { teachingtools / question } {
    label .choice:,
    label / arabic .code:n = {
        \tl_set:Nn \l__teachingtools_question_label_tl { \arabic{question} }
    },
    label / alph .code:n = {
        \tl_set:Nn \l__teachingtools_question_label_tl { \int_to_alph:n { \value{question} } }
    },
    label / lower-alph .code:n = {
        \tl_set:Nn \l__teachingtools_question_label_tl { \int_to_alph:n { \value{question} } }
    },
    label / upper-alph .code:n = {
        \tl_set:Nn \l__teachingtools_question_label_tl { \int_to_Alph:n { \value{question} } }
    },
    label / roman .code:n = {
        \tl_set:Nn \l__teachingtools_question_label_tl { \roman{question} }
    },
    label / lower-roman .code:n = {
        \tl_set:Nn \l__teachingtools_question_label_tl { \roman{question} }
    },
    label / upper-roman .code:n = {
        \tl_set:Nn \l__teachingtools_question_label_tl { \Roman{question} }
    },
    label .default:n = arabic,
    label .initial:n = arabic,
}
\str_new:N \l__teachingtools_suffix_character_str
\keys_define:nn { teachingtools } {
    suffix-character .choice:,
    suffix-character / dot .code:n = {
        \str_set:Nn \l__teachingtools_suffix_character_str { . }
    },
    suffix-character / colon .code:n = {
        \str_set:Nx \l__teachingtools_suffix_character_str { \c_colon_str }
    },
    suffix-character / bracket .code:n = {
        \str_set:Nx \l__teachingtools_suffix_character_str { ) }
    },
    suffix-character / none .code:n = {
        \str_gclear:N \l__teachingtools_suffix_character_str
    },
    suffix-character .default:n = dot,
    suffix-character .initial:n = dot,
}
\skip_new:N \l__teachingtools_questionbefore_skip
\skip_new:N \l__teachingtools_questionafter_skip

\skip_set:Nn \l__teachingtools_questionbefore_skip { 1.0ex plus -1ex minus -0.25ex }
\skip_set:Nn \l__teachingtools_questionafter_skip { 1ex plus 0.25ex }

\NewDocumentEnvironment { question } { s O { } } {
    \IfBooleanTF #1
    { \bool_set_false:N \l__teachingtools_numbered_question_bool }
    { \bool_set_true:N \l__teachingtools_numbered_question_bool }

    \keys_set:nn { teachingtools / question } {#2}
    \__teachingtools_print_question:

    \itshape
    }
{\par \skip_vertical:N \l__teachingtools_questionafter_skip \thequestion} % The `\thequestion` here is simply to illustrate the changing definition

\NewDocumentCommand \ttsetup { m } {
    \keys_set:nn { teachingtools } {#1}
}
\ProcessKeysOptions { teachingtools }
\ExplSyntaxOff

\begin{document}

% Most options set with `\ttsetup` can also be applied on specific instances
% of the `question` environment.  Of most use in this scenario is the
% `number` option, which has the same effect as `\setcounter{question}`; the
% others are of limited use but I've made them available anyway.
\ttsetup{
    % prefix-separator = dash,             % (dash|dot|colon|none)
    question / prefix = section,           % (part|chapter|section|subsection|subsubsection|paragraph|subparagraph|none)
    question / reset = none,               % (part|chapter|section|subsection|subsubsection|paragraph|subparagraph|none)
    question / label = upper-alph,         % (arabic|lower-alph|upper-alph|lower-roman|upper-roman)
    suffix-character = bracket,            % (dot|colon|bracket|none)
    % question / number = 1,               % any integer
}

\section{A section}

\begin{question}
    The question in a section
\end{question}

\thequestion  % Should be 1-A, prints 1 instead

\subsection{A subsection}

\begin{question}
    The question in a subsection
\end{question}

\begin{question}[number = 7]
    Another question in a subsection
\end{question}

\subsubsection{A subsubsection}

\begin{question}\label{qu:test}
    The question in a subsubsection
\end{question}

\begin{question}
    Another question in a subsubsection
\end{question}

\section{Another section}

\begin{question}
    Another question in another section
\end{question}

See also \ref{qu:test}.

\begin{question}
    Another question in another section
\end{question}

\subsection{A subsection}

\begin{question}
    The question in a subsection
\end{question}

\begin{question}
    Another question in a subsection
\end{question}

\begin{question}
    Another question in a subsection
\end{question}

\subsubsection{A subsubsection}

\begin{question}
    The question in a subsubsection
\end{question}

\begin{question}
    Another question in a subsubsection
\end{question}

\subsubsection{A subsubsection}

\begin{question}
    The question in a subsubsection
\end{question}

\begin{question}
    Another question in a subsubsection
\end{question}

\end{document}

简而言之,此包将定义环境以排版问题/答案对,以及其他一些内容,用于学术工作表,如教程、教科书、考试、讲义等。为了提供最大的灵活性,这些环境的编号样式可以动态更改,可以使用专用命令或通过将选项传递给环境实例来更改。上面的 MWE 可以执行这些操作,可以通过更改宏中的各种选项来演示\ttsetup

我目前的问题是,我还想改变打印标记引用的方式question,以便如果问题编号为 3-B,则参考资料将打印“3-B”而不是“2”。这可能吗?如果可以,我该怎么做?我一直在研究cleveref一些提示,但我想我需要在下面的级别进行修改;一旦我开始工作,我总是可以稍后添加补丁cleveref

到目前为止,我已经设法让它在终端中打印出正确的标签格式,使用字符串\l__teachingtools_question_label_format_tl\renewcommand{\thequestion}通过 l3→2e 包装器宏将其传递给它,结果以相当奇怪的方式中断,这是可以预料到的。我的直觉是,我已经完成了一部分,但我对 2e 或 l3 的了解还远远不够,无法让接口以合理的方式运行。

答案1

这段代码似乎可以解决问题。\g__teachingtools_question_label_format_tl需要由单独的函数呈现,然后在文档开头调用一次以生成初始值。之后,每次创建问题环境时都会重新生成它,这样就可以正确设置引用。

% arara: lualatex
% arara: lualatex
\documentclass{article}
\usepackage{xparse}
\usepackage{expl3}
\usepackage{l3keys2e}
\usepackage{chngcntr}

\setlength\parindent{0pt}

\ExplSyntaxOn

\cs_new:Nn \__teachingtools_print_question: {
    \teachingtools_generate_question_label_format:
    \str_clear_new:N \l__teachingtools_question_str
    \str_put_left:Nn \l__teachingtools_question_str { Question }
    \bool_if:NT \l__teachingtools_numbered_question_bool {
        \refstepcounter{question}
        \str_put_right:Nn \l__teachingtools_question_str { ~ }
        \__teachingtools_print_question_label:
        \str_put_right:Nx \l__teachingtools_question_str { \l__teachingtools_question_label_str }
    }
    \str_put_right:Nx \l__teachingtools_question_str { \l__teachingtools_suffix_character_str }

    % Prints format string of label in terminal: how can I use this to change the
    % printing of \refl{qu:label}?
    % \tl_show:N \l__teachingtools_question_label_format_tl
    % \cs_gset_nopar:cpx { thequestion } { } { \l__teachingtools_question_label_format_tl }

    \par \skip_vertical:N \l__teachingtools_questionbefore_skip
    \group_begin:
    \bfseries \l__teachingtools_question_str \par\nopagebreak
    \group_end:
}
\cs_new:Nn \__teachingtools_print_question_label: {
    \str_clear_new:N \l__teachingtools_question_label_str
    \bool_if:NT \l__teachingtools_question_prefix_bool {
        \str_put_right:Nx \l__teachingtools_question_label_str { \l__teachingtools_question_prefix_tl }
        \str_put_right:Nx \l__teachingtools_question_label_str { \l__teachingtools_prefix_separator_str }
        \tl_gput_right:NV \g__teachingtools_question_label_format_tl { \l__teachingtools_question_prefix_tl }
        \tl_gput_right:NV \g__teachingtools_question_label_format_tl { \l__teachingtools_prefix_separator_str }
    }
    \str_put_right:Nx \l__teachingtools_question_label_str { \l__teachingtools_question_label_tl }
    \tl_gput_right:NV \g__teachingtools_question_label_format_tl { \l__teachingtools_question_label_tl }
}
\tl_new:N \g__teachingtools_question_label_format_tl
\cs_new:Nn \teachingtools_generate_question_label_format: {
    \tl_gclear:N \g__teachingtools_question_label_format_tl
    \bool_if:NT \l__teachingtools_question_prefix_bool {
        \tl_gput_right:NV \g__teachingtools_question_label_format_tl { \l__teachingtools_question_prefix_tl }
        \tl_gput_right:NV \g__teachingtools_question_label_format_tl { \l__teachingtools_prefix_separator_str }
    }
    \tl_gput_right:NV \g__teachingtools_question_label_format_tl { \l__teachingtools_question_label_tl }
}
\newcounter{question}
\keys_define:nn { teachingtools / question } {
    reset .default:n = section,
    reset .choices:nn = {
        part, chapter, section, subsection, subsubsection, paragraph, subparagraph
    }
    {
        \counterwithin*{question}{ \tl_to_str:N \l_keys_choice_tl }
    },
    reset / none .code:n = {
        \counterwithout*{question}{section}
    },
}
\bool_new:N \l__teachingtools_numbered_question_bool
\keys_define:nn { teachingtools } {
    question / number .code:n = {
        \int_set_eq:NN \l_tmpa_int #1
        \int_decr:N \l_tmpa_int
        \setcounter{question}{ \int_use:N \l_tmpa_int }
    },
}
\str_new:N \l__teachingtools_prefix_separator_str
\keys_define:nn { teachingtools } {
    prefix-separator .choice:,
    prefix-separator / dash .code:n = {
        \str_set:Nn \l__teachingtools_prefix_separator_str { - }
    },
    prefix-separator / dot .code:n = {
        \str_set:Nn \l__teachingtools_prefix_separator_str { . }
    },
    prefix-separator / colon .code:n = {
        \str_set:Nx \l__teachingtools_prefix_separator_str { \c_colon_str }
    },
    prefix-separator / none .code:n = {
        \str_gclear:N \l__teachingtools_prefix_separator_str
    },
    prefix-separator .default:n = none,
    prefix-separator .initial:n = none,
}
\tl_new:N \l__teachingtools_question_prefix_tl
\bool_new:N \l__teachingtools_question_prefix_bool
\keys_define:nn { teachingtools / question } {
    prefix .choice:,
    prefix / part .code:n = {
        \tl_set:Nn \l__teachingtools_question_prefix_tl { \thepart }
        \keys_set:nn { teachingtools } {
            question / reset = part,
            prefix-separator = dash,
        }
        \bool_set_true:N \l__teachingtools_question_prefix_bool
    },
    prefix / chapter .code:n = {
        \tl_set:Nn \l__teachingtools_question_prefix_tl { \thechapter }
        \keys_set:nn { teachingtools } {
            question / reset = chapter,
            prefix-separator = dash,
        }
        \bool_set_true:N \l__teachingtools_question_prefix_bool
    },
    prefix / section .code:n = {
        \tl_set:Nn \l__teachingtools_question_prefix_tl { \thesection }
        \keys_set:nn { teachingtools } {
            question / reset = section,
            prefix-separator = dash,
        }
        \bool_set_true:N \l__teachingtools_question_prefix_bool
    },
    prefix / subsection .code:n = {
        \tl_set:Nn \l__teachingtools_question_prefix_tl { \thesubsection }
        \keys_set:nn { teachingtools } {
            question / reset = subsection,
            prefix-separator = dash,
        }
        \bool_set_true:N \l__teachingtools_question_prefix_bool
    },
    prefix / subsubsection .code:n = {
        \tl_set:Nn \l__teachingtools_question_prefix_tl { \thesubsubsection }
        \keys_set:nn { teachingtools } {
            question / reset = subsubsection,
            prefix-separator = dash,
        }
        \bool_set_true:N \l__teachingtools_question_prefix_bool
    },
    prefix / paragraph .code:n = {
        \tl_set:Nn \l__teachingtools_question_prefix_tl { \theparagraph }
        \keys_set:nn { teachingtools } {
            question / reset = paragraph,
            prefix-separator = dash,
        }
        \bool_set_true:N \l__teachingtools_question_prefix_bool
    },
    prefix / subparagraph .code:n = {
        \tl_set:Nn \l__teachingtools_question_prefix_tl { \thesubparagraph }
        \keys_set:nn { teachingtools } {
            question / reset = subparagraph,
            prefix-separator = dash,
        }
        \bool_set_true:N \l__teachingtools_question_prefix_bool
    },
    prefix / none .code:n = {
        \tl_gclear:N \l__teachingtools_question_prefix_tl
    },
    prefix .default:n = none,
    prefix .initial:n = none,
}
\tl_new:N \l__teachingtools_question_label_tl
\keys_define:nn { teachingtools / question } {
    label .choice:,
    label / arabic .code:n = {
        \tl_set:Nn \l__teachingtools_question_label_tl { \arabic{question} }
    },
    label / alph .code:n = {
        \tl_set:Nn \l__teachingtools_question_label_tl { \int_to_alph:n { \value{question} } }
    },
    label / lower-alph .code:n = {
        \tl_set:Nn \l__teachingtools_question_label_tl { \int_to_alph:n { \value{question} } }
    },
    label / upper-alph .code:n = {
        \tl_set:Nn \l__teachingtools_question_label_tl { \int_to_Alph:n { \value{question} } }
    },
    label / roman .code:n = {
        \tl_set:Nn \l__teachingtools_question_label_tl { \roman{question} }
    },
    label / lower-roman .code:n = {
        \tl_set:Nn \l__teachingtools_question_label_tl { \roman{question} }
    },
    label / upper-roman .code:n = {
        \tl_set:Nn \l__teachingtools_question_label_tl { \Roman{question} }
    },
    label .default:n = arabic,
    label .initial:n = arabic,
}
\str_new:N \l__teachingtools_suffix_character_str
\keys_define:nn { teachingtools } {
    suffix-character .choice:,
    suffix-character / dot .code:n = {
        \str_set:Nn \l__teachingtools_suffix_character_str { . }
    },
    suffix-character / colon .code:n = {
        \str_set:Nx \l__teachingtools_suffix_character_str { \c_colon_str }
    },
    suffix-character / bracket .code:n = {
        \str_set:Nx \l__teachingtools_suffix_character_str { ) }
    },
    suffix-character / none .code:n = {
        \str_gclear:N \l__teachingtools_suffix_character_str
    },
    suffix-character .default:n = dot,
    suffix-character .initial:n = dot,
}
\skip_new:N \l__teachingtools_questionbefore_skip
\skip_new:N \l__teachingtools_questionafter_skip

\skip_set:Nn \l__teachingtools_questionbefore_skip { 1.0ex plus -1ex minus -0.25ex }
\skip_set:Nn \l__teachingtools_questionafter_skip { 1ex plus 0.25ex }

\NewDocumentEnvironment { question } { s O { } } {
    \IfBooleanTF #1
    { \bool_set_false:N \l__teachingtools_numbered_question_bool }
    { \bool_set_true:N \l__teachingtools_numbered_question_bool }

    \keys_set:nn { teachingtools / question } {#2}
    \__teachingtools_print_question:

    \itshape
    }
{\par \skip_vertical:N \l__teachingtools_questionafter_skip }
\cs_new:cpn {question*} {\question*}
\cs_new_eq:cN {endquestion*} \endquestion

\NewDocumentCommand \ttsetup { m } {
    \keys_set:nn { teachingtools } {#1}
}
\ProcessKeysOptions { teachingtools }

\renewcommand\thequestion{ \g__teachingtools_question_label_format_tl }

\ExplSyntaxOff

\usepackage{hyperref}
\hypersetup{
    colorlinks=false,
    hidelinks}
\usepackage[all]{hypcap}

\begin{document}

% Most options set with `\ttsetup` can also be applied on specific instances
% of the `question` environment.  Of most use in this scenario is the
% `number` option, which has the same effect as `\setcounter{question}`; the
% others are of limited use but I've made them available anyway.
\ttsetup{
    % prefix-separator = dash,             % (dash|dot|colon|none)
    question / prefix = section,           % (part|chapter|section|subsection|subsubsection|paragraph|subparagraph|none)
    question / reset = none,               % (part|chapter|section|subsection|subsubsection|paragraph|subparagraph|none)
    question / label = lower-alph,         % (arabic|lower-alph|upper-alph|lower-roman|upper-roman)
    suffix-character = dot,                % (dot|colon|bracket|none)
    % question / number = 1,               % any integer
}

\section{A section}

\begin{question}\label{qu:first}
    The question in a section
\end{question}

\subsection{A subsection}

\begin{question}
    The question in a subsection
\end{question}

\begin{question}[number = 7, label = lower-roman]\label{qu:lowerroman}
    Another question in a subsection
\end{question}

\subsubsection{A subsubsection}

\begin{question}\label{qu:test}
    The question in a subsubsection
\end{question}

\begin{question}
    Another question in a subsubsection
\end{question}

\section{Another section}

\begin{question}
    Another question in another section, which refers to
    \ref{qu:lowerroman}.
\end{question}

See also \ref{qu:test}, and \ref{qu:first}.

\begin{question}
    Another question in another section
\end{question}

\subsection{A subsection}

\begin{question}
    The question in a subsection
\end{question}

\begin{question}
    Another question in a subsection
\end{question}

\begin{question}
    Another question in a subsection
\end{question}

\subsubsection{A subsubsection}

\begin{question}
    The question in a subsubsection
\end{question}

\begin{question}
    Another question in a subsubsection
\end{question}

\subsubsection{A subsubsection}

\begin{question}
    The question in a subsubsection
\end{question}

\begin{question}
    Another question in a subsubsection
\end{question}

\end{document}

相关内容