定义具有多个参数的变量

定义具有多个参数的变量

如何定义变量\var{arg1: Name}{arg2: Family}并在文本中使用类似

我的名字是\var$arg1,我的家人是\var$arg2

arg1arg2是参数的标签。

答案1

尽管你的想法与 TeX 中使用的典型语法相差甚远,但这是可能的。\var$arg1这里只通过(添加分号)更改了使用语法\var$arg1;,因为我们需要知道参数名称的终止位置。

\def\var{\futurelet\next\varA}
\def\varA{\let\varB=\relax
   \ifx\next$\let\varB=\varC\fi %$
   \ifx\next\bgroup\let\varB=\varD\fi
   \varB
}
\def\varC$#1;{\csname var:#1\endcsname} %$
\def\varD#1{\varE#1\end\var}
\def\varE#1: #2\end{\expandafter\def\csname var:#1\endcsname{#2}}

\var{arg1: Name}{arg2: Family}

My name is \var$arg1; and my family is \var$arg2;.

\bye

答案2

您可以定义一个属性列表,并向其中添加名称以及用于检索它们的键。

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\prop_new:N \g_amin_names_prop

\NewDocumentCommand{\defineperson}{mmm}
 {
  \prop_gput:Nnn \g_amin_names_prop { #1-name } { #2 }
  \prop_gput:Nnn \g_amin_names_prop { #1-family } { #3 }
 }

\NewDocumentCommand{\personname}{m}
 {
  \prop_item:Nn \g_amin_names_prop { #1-name }
 }
\NewDocumentCommand{\personfamily}{m}
 {
  \prop_item:Nn \g_amin_names_prop { #1-family }
 }

\ExplSyntaxOff

\defineperson{amin}{Amin}{Roshani}
\defineperson{blu}{Ben}{User}

\begin{document}

My name is \personname{amin}, my family is \personfamily{amin}.

My best friend is \personname{blu} \personfamily{blu}.

\end{document}

在此处输入图片描述

答案3

几个月前我写了一个\SetProperty--\GetProperty界面。

这个概念是关于维护扩展为 2 元组参数列表的宏。
此类元组的第一个组件保存属性的名称。第二个组件保存属性的值。

维护这些宏的“用户界面”由两个控制序列组成:

\SetProperty{\macro}{<name of property>}{<new value of property>}

\GetProperty{\macro}{<name of property>}{<tokens to be delivered in case property is not available>}

例如,

\SetProperty{\foobar}{Property A}{Property A's value}
\SetProperty{\foobar}{Property B}{Property B's value}    

将使宏\foobar扩展为

{{Property A}{Property A's value}}% <- 1st 2-tuple
{{Property B}{Property B's value}}% <- 2nd 2-tuple

例如,

\GetProperty{\foobar}{Property A}{Property A not available in \texttt{\string\foobar}}

将扩展为:

Property A's value

例如,

\GetProperty{\foobar}{Property C}{Property C not available in \texttt{\string\foobar}}

将扩展为:

Property C not available in \texttt{\string\foobar}

但属性 C 将在以下情况下可用:

\SetProperty{\foobar}{Property C}{Property C's value}

,因此说完之后,\foobar会扩展为

{{Property A}{Property A's value}}% <- 1st 2-tuple
{{Property B}{Property B's value}}% <- 2nd 2-tuple
{{Property C}{Property C's value}}% <- 3rd 2-tuple    

\GetProperty{\foobar}{Property C}{Property C not available in \texttt{\string\foobar}}

则结果为:

Property C's value

更详细的解释位于下面包含整个接口编码的示例的注释中:

%% This coding example
%%  - was written by Ulrich Diez in December 14, 2016
%%  - was modified by Ulrich Diez in April 07, 2017
%%  - Copyright 2016, 2017 Ulrich Diez
%%                   (e-mail: [email protected])
%%
%% This work may be distributed and/or modified under the conditions of
%% the LaTeX Project Public License, either version 1.3c of this license
%% or (at your option) any later version.
%%
%% The latest version of this license is in
%%
%%   <http://www.latex-project.org/lppl.txt>
%%
%% and version 1.3x or later is part of all distributions of LaTeX
%% version 2005/12/01 or later.
%%
%% This work has the LPPL maintenance status `unmaintained'.
%%
%% This work consists of this coding example.
%%
\errorcontextlines=10000
\documentclass{article}


\makeatletter
%%==== Begin of code for the \SetProperty-\GetProperty-Interface =======
\RequirePackage{ifluatex, ifxetex}
%%======================================================================
%% Paraphernalia:
%%    \UD@firstoftwo, \UD@secondoftwo, \UD@PassFirstToSecond,
%%    \UD@exchange, \UD@removespace, \UD@name, \UD@CheckWhetherNull,
%%    \UD@loopcall,
%%......................................................................
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
\newcommand\UD@exchange[2]{#2#1}%
\newcommand\UD@removespace{}\UD@firstoftwo{\def\UD@removespace}{} {}%
%%----------------------------------------------------------------------
%% Put a control sequence token in place instead of the string denoting
%% its name.
%%......................................................................
%%  \UD@name<emptiness or tokens other than braces>{<Name of
%%                                                   Control Sequence>}
%%
%% yields:
%%
%%  <emptiness or tokens other than braces>\Controlsequence
%%
%% E.g.,
%%
%%   \UD@name foo{bar} -> foo\bar
%%   \UD@name{bar} -> \bar
%%   \UD@name\newcommand*{wEirdName}[1]{Arg 1: (#1)}
%%       -> \newcommand*\wEirdName[1]{Arg 1: (#1)}
%%
\newcommand\UD@name{}\long\def\UD@name#1#{\romannumeral\UD@@name{#1}}%
\newcommand\UD@@name[2]{%
  \expandafter\UD@exchange\expandafter{\csname#2\endcsname}{0 #1}%
}%
%%----------------------------------------------------------------------
%% Check whether argument is empty:
%%......................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
%%
%% (\romannumeral expansion was introduced in order to overcome the
%%  concerns and worries about improperly balanced
%%  \if..\else..\fi constructs.)
%%
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
  \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{%
  \expandafter\UD@secondoftwo\string}\expandafter\expandafter
  \UD@firstoftwo{ }{}\UD@secondoftwo}{\expandafter\expandafter
  \UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%----------------------------------------------------------------------
%% Expandable Loop:
%% \UD@loopcall{<action>}%
%%          {<action if list empty>}%
%%          {<preset>}%
%%          {{<e_k>}{<e_(k+1)>}..{e_n}}% <- this is the list
%%
%% If list is empty: <action if list empty>
%% Else:
%% <action>{<e_k>}<preset> \UD@loopcall{<action>}%
%%                                  {<action if list empty>}%
%%                                  {<preset>}{{<e_(k+1)>}..{e_n}}
%%
%% <action> can be defined to mesh into the iteration-process, e.g.,
%% (ex)changing arguments like the <action if list empty>-argument for
%% the next \UD@loopcall-iteration, e.g., terminating iteration
%% prematurely under some circumstances.
%%......................................................................
\newcommand\UD@RemoveTillUD@nil{}%
\long\def\UD@RemoveTillUD@nil#1#2\UD@nil{{#1}}%
\newcommand\UD@Extractfirstloop[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
  {\UD@exchange{#1}}%
  {%
    \expandafter\UD@Extractfirstloop
    \expandafter{\UD@RemoveTillUD@nil#1}%
  }%
}%
\newcommand\UD@loopcall[4]{%
  \UD@CheckWhetherNull{#4}{#2}{%
    \expandafter\UD@exchange
    \expandafter{\expandafter{\UD@firstoftwo{}#4}}%
    {\UD@Extractfirstloop{#4\UD@nil}{#1}#3\UD@loopcall{#1}{#2}{#3}}%
  }%
}%
%%======================================================================
%% Expandable comparison of two strings:
%%
%% Derived from David Kastrup's \ifstrequal-test from the
%% TeX Pearl Diving Site;
%% Pearls of 2005;
%% Title: David Kastrup - Comparing two strings known to consist
%% only of characters ;
%% Url: <http://www.gust.org.pl/projects/pearls/2005p/david-kastrup/bachotex2005-david-kastrup-pearl1.pdf>
%%......................................................................
%% \\UD@ifstrequal{<String 1>}{<String 2>}%
%%                {%
%%                   <Tokens to be delivered in case strings are equal>
%%                }%
%%                {%
%%                   <Tokens to be delivered in case strings are
%%                    not equal>
%%                }%
%%
%% (<String 1> gets expanded during comparison.
%%  <String 2> gets not expanded during comparison.
%%
%% I bloated this thing up for ensuring it also takes spaces into
%% account.
%%
\@ifdefinable\UD@strchksp{%
  \long\def\UD@strchksp#1#2#3#4 #5\relax{%
    #1{\if\UD@strequal\UD@secondoftwo{}{#4}%
       \expandafter\UD@firstoftwo\else\expandafter\UD@secondoftwo\fi
       {\if\UD@strequal\UD@secondoftwo{}{#5}%
        \expandafter\UD@firstoftwo\else\expandafter\UD@secondoftwo\fi
        {\UD@strequalstart#1{#2}{#3} \relax}%
        {\UD@strequalstart#1{#2}{#3}{ }#5\relax}}}%
    {\UD@strequalstart#1{#2}{#3}#4 #5\relax}%
  }%
}
\newcommand\UD@strequal[2]{\number\UD@strchksp#1{}{}#2 \relax}
\newcommand\UD@strequalstart[4]{%
  \if#4\relax\UD@strequalstop\fi
  \UD@strchksp#1{\if#4#2}{#3\fi}%
}%
\@ifdefinable\UD@strequalstop{%
  \long\def\UD@strequalstop\fi\UD@strchksp#1#2#3#4{\fi#2#4\relax'#313 }%
}
\newcommand\UD@ifstrequal[2]{%
  \romannumeral0%
  \if\UD@strequal\@firstofone{#2.}{#1.}%
  \expandafter\UD@firstoftwo\else\expandafter\UD@secondoftwo\fi
  {\UD@exchange{ \UD@firstoftwo}}{\UD@exchange{ \UD@secondoftwo}}%
  {\expandafter\expandafter\expandafter}%
}%
%%======================================================================
%% Total expansion and stringification of argument:
%%......................................................................
%% \UD@stringify{<argument that expands to character tokens>}
%%
%% Does \csname..\endcsname with the argument, then \string,
%% then removal of \escapechar if that was added.
%%
\newcommand\UD@stringify[1]{%
  \romannumeral0%
  \expandafter\expandafter\expandafter\UD@exchange
  \expandafter\expandafter\expandafter{%
  \expandafter\string\csname#1\endcsname}%
  {%
    \ifnum\the\escapechar<0 %
    \expandafter\UD@secondoftwo\else\expandafter\UD@firstoftwo\fi
    {%
      \ifnum\the\escapechar>\ifxetex 1114111 %
      \else\ifluatex 1114111 \else 255 \fi\fi
      \expandafter\UD@secondoftwo\else\expandafter\UD@firstoftwo\fi
      {%
        \ifnum\the\escapechar=32 %
        \expandafter\UD@secondoftwo\else\expandafter\UD@firstoftwo\fi
        {\UD@firstoftwo{ }}{}%
      }{ }%
    }{ }%
  }%
}%
%%======================================================================
%% Property-Management:
%%......................................................................
%%
%% The concept is about maintaining macros that expand to lists of
%% 2-tuple-arguments.
%% The first component of the tuple holds the name of a property.
%% The second component holds the value of the property.
%%
%% E.g., the macro \macro could be defined to expand to:
%%
%%   {{property name 1}{property value 1}}%
%%   {{property name 2}{property value 2}}%
%%   ...
%%   {{property name K}{property value K}}%
%%
%%
%% \SetProperty{\macro}%
%%             {<name of property>}%
%%             {<new value of property>}
%%
%%   In case \macro is undefined, \macro will be defined empty.
%%
%%   In case a property <name of property> does not exist within the
%%   macro \macro, it will be added to the macro and it will get the
%%   value <new value of property>.
%%
%%   In case a property <name of property> does exist within the macro
%%   \macro, its value will get replaced by <new value of property>.
%%
%%   Before further evaluation <name of property> will be expanded via
%%   \csname..\endcsname-expansion and afterwards "stringified" by
%%   applying \string and removing a leading escapechar if one was
%%   added.
%%
%%   Example:
%%
%%     \SetProperty{\macro}{property name 2}{changed property value 2}
%%
%%        would make \macro to expand to
%%
%%     {{property name 1}{property value 1}}%
%%     {{property name 2}{changed property value 2}}%
%%     ...
%%     {{property name K}{property value K}}%
%%
%%       and
%%
%%     \SetProperty{\macro}{property name (K+1)}{property value (K+1)}
%%
%%        would make \macro to expand to
%%
%%     {{property name 1}{property value 1}}%
%%     {{property name 2}{changed property value 2}}%
%%     ...
%%     {{property name K}{property value K}}%
%%     {{property name (K+1)}{property value (K+1)}}%
%%
%%
%% \GetProperty{\macro}%
%%             {<name of property>}%
%%             {%
%%               <tokens to be delivered in case
%%                property is not available>
%%             }
%%
%%   In case \macro is undefined or property <name of property> does not
%%   exist within the macro \macro,
%%   <tokens to be delivered in case property is not available>
%%   will be delivered.
%%
%%   In case a property <name of property> does exist within the macro
%%   \macro, its value will be delivered.
%%
%%   Before further evaluation <name of property> will be expanded via
%%   \csname..\endcsname-expansion and afterwards "stringified" by
%%   applying \string and removing a leading escapechar if one was
%%   added.
%%
%%   \GetProperty is expandable and delivers the result after two
%%   expansion steps / after being hit "twice" by \expandafter.
%%
%%   E.g., with the macro \macro being defined to expand to
%%
%%     {{property name 1}{property value 1}}%
%%     {{property name 2}{property value 2}}%
%%     ...
%%     {{property name K}{property value K}}%
%%
%%   , the sequence
%%
%%     \GetProperty{\macro}{property name 2}{Huh?}
%%
%%   will expand to:
%%
%%     property value 2
%%
\newcommand\UD@ExpandProperties[3]{%
  \expandafter\UD@PassFirstToSecond\expandafter{#1}%
  {\expandafter\expandafter\expandafter\UD@PassFirstToSecond
  \expandafter\expandafter\expandafter{%
  \UD@stringify{#2}}{#3}}%
}%
\newcommand\UD@AtIfPropertyListUndefined[1]{%
  \@ifundefined{%
    \expandafter\UD@exchange\expandafter{\string#1}%
    {%
      \ifnum\the\escapechar<0 %
      \expandafter\UD@secondoftwo\else\expandafter\UD@firstoftwo\fi
      {%
        \ifnum\the\escapechar>\ifxetex 1114111 %
        \else\ifluatex 1114111 \else 255 \fi\fi
        \expandafter\UD@secondoftwo\else\expandafter\UD@firstoftwo\fi
        {%
          \ifnum\the\escapechar=32 %
          \expandafter\UD@secondoftwo\else\expandafter\UD@firstoftwo\fi
          {\UD@firstoftwo{}}{\UD@removespace}%
        }{}%
      }{}%
    }%
  }
}%
\newcommand\SetProperty[2]{%
  \@bsphack
  \UD@AtIfPropertyListUndefined{#1}{\newcommand*#1{}}{}%
  \romannumeral0%
  \UD@ExpandProperties{#1}{#2}{\UD@@setproperty}{#1}%
}%
\newcommand\UD@@setproperty[4]{%
  \UD@loopcall{\UD@@@setproperty}%
              { \def#3{{{#1}{#4}}}\@esphack}%
              {{#1}{#4}{ \def#3}{}}%
              {#2}%
}%
\newcommand\UD@@@setproperty{}%
\long\def\UD@@@setproperty#1#2#3#4#5\UD@loopcall#6#7#8#9{%
  \UD@ifstrequal{\UD@firstoftwo#1}{#2}%
  {%
    #4{#5{{#2}{#3}}#9}\@esphack
  }{%
    \UD@loopcall{#6}%
                {#4{#5{#1}{{#2}{#3}}}\@esphack}%
                {{#2}{#3}{#4}{#5{#1}}}%
                {#9}%
  }%
}%
\newcommand\GetProperty[3]{%
  \romannumeral0%
  \UD@AtIfPropertyListUndefined{#1}{ #3}{%
    \UD@ExpandProperties{#1}{#2}{\UD@@getproperty}{ #3}%
  }%
}%
\newcommand\UD@@getproperty[3]{%
  \UD@loopcall{\UD@@@getproperty}%
              {#3}%
              {{#1}}%
              {#2}%
}%
\newcommand\UD@@@getproperty{}%
\long\def\UD@@@getproperty#1#2\UD@loopcall#3#4#5#6{%
  \UD@ifstrequal{\UD@firstoftwo#1}{#2}%
    {\UD@exchange{ }\expandafter\UD@secondoftwo#1}%
    {%
      \UD@loopcall{#3}%
                  {#4}%
                  {#5}%
                  {#6}%
    }%
}%
%%==== End of code for the \SetProperty-\GetProperty-Interface =========
\makeatother

%%==== Layout of this example ==========================================
%   - No headers / no footers
\pagestyle{empty}
%   - horizontal margins:
\parindent=0ex
\setlength\textwidth{\paperwidth}
\addtolength\textwidth{-3cm}
\setlength\oddsidemargin{1.5cm}%
\addtolength\oddsidemargin{-1in}%
\addtolength\oddsidemargin{-\hoffset}%
\setlength\evensidemargin{\oddsidemargin}%
\setlength\marginparwidth{1.5cm}%
\addtolength\marginparwidth{-2\marginparsep}%
%   - vertical margins:
\setlength\topmargin{1.5cm}
\addtolength\topmargin{-1in}
\addtolength\topmargin{-\voffset}
%   - no headheight/headsep etc as there are no headers as
%     pagestyle=empty:
\setlength\headsep{0pt}
\setlength\headheight{0pt}
\setlength\footskip{0pt}
\setlength\textheight{\paperheight}
\addtolength\textheight{-3cm}%
\addtolength\textheight{-\footskip}%
\addtolength\textheight{-\headsep}%
\addtolength\textheight{-\headheight}%
%   - allow linebreaks after closing braces in typewriter font:
\DeclareFontFamily{\encodingdefault}{\ttdefault}{\hyphenchar\font=`\}}
%   - in case of pdftex also adjust the underlying paper
\expandafter\ifx\csname pdfpagewidth\endcsname\relax\else
  \pdfpagewidth=\paperwidth
  \pdfpageheight=\paperheight
\fi
%%==== Layout-changes etc done.=========================================

\begin{document}

\sloppy

\verb|\SetProperty{\myNicePropertyList}{name}{Mme Xample}|:\\
\SetProperty{\myNicePropertyList}{name}{Mme Xample}
\texttt{\string\myNicePropertyList: \meaning\myNicePropertyList}
\bigskip

\verb|\SetProperty{\myNicePropertyList}{position}{Manager}:|\\
\SetProperty{\myNicePropertyList}{position}{Manager}
\texttt{\string\myNicePropertyList: \meaning\myNicePropertyList}
\bigskip

\verb|\SetProperty{\myNicePropertyList}{company}{Example Company}|:\\
\SetProperty{\myNicePropertyList}{company}{Example Company}
\texttt{\string\myNicePropertyList: \meaning\myNicePropertyList}
\bigskip

\verb|\SetProperty{\myNicePropertyList}{street}{11 Xample Street}|:\\
\SetProperty{\myNicePropertyList}{street}{11 Xample Street}
\texttt{\string\myNicePropertyList: \meaning\myNicePropertyList}
\bigskip

\verb|\SetProperty{\myNicePropertyList}{location}{Xample Ville}|:\\
\SetProperty{\myNicePropertyList}{location}{Xample Ville}
\texttt{\string\myNicePropertyList: \meaning\myNicePropertyList}
\bigskip

\verb|\SetProperty{\myNicePropertyList}{postal code}{SW1E 6LB}|:\\
\SetProperty{\myNicePropertyList}{postal code}{SW1E 6LB}
\texttt{\string\myNicePropertyList: \meaning\myNicePropertyList}
\bigskip

\verb|\SetProperty{\myNicePropertyList}{country}{EXAMPLISTAN}|:\\
\SetProperty{\myNicePropertyList}{country}{EXAMPLISTAN}
\texttt{\string\myNicePropertyList: \meaning\myNicePropertyList}
\vfill

\verb|\GetProperty{\myNicePropertyList}{name}{DATA NOT AVAILABLE}|:
\GetProperty{\myNicePropertyList}{name}{DATA NOT AVAILABLE}
\smallskip

\verb|\GetProperty{\myNicePropertyList}{position}{DATA NOT AVAILABLE}|:
\GetProperty{\myNicePropertyList}{position}{DATA NOT AVAILABLE}
\smallskip

\verb|\GetProperty{\myNicePropertyList}{company}{DATA NOT AVAILABLE}|:
\GetProperty{\myNicePropertyList}{company}{DATA NOT AVAILABLE}
\smallskip

\verb|\GetProperty{\myNicePropertyList}{street}{DATA NOT AVAILABLE}|:
\GetProperty{\myNicePropertyList}{street}{DATA NOT AVAILABLE}
\smallskip

\verb|\GetProperty{\myNicePropertyList}{location}{DATA NOT AVAILABLE}|:
\GetProperty{\myNicePropertyList}{location}{DATA NOT AVAILABLE}
\smallskip

\verb|\GetProperty{\myNicePropertyList}{postal code}{DATA NOT AVAILABLE}|:
\GetProperty{\myNicePropertyList}{postal code}{DATA NOT AVAILABLE}
\smallskip

\verb|\GetProperty{\myNicePropertyList}{country}{DATA NOT AVAILABLE}|:
\GetProperty{\myNicePropertyList}{country}{DATA NOT AVAILABLE}
\smallskip

\verb|\GetProperty{\myNicePropertyList}{an undefined property}{DATA NOT AVAILABLE}:|
\GetProperty{\myNicePropertyList}{an undefined property}%
                                 {DATA NOT AVAILABLE}
\smallskip

\verb|\GetProperty{\UndefinedPropertyList}{name}{DATA NOT AVAILABLE}:|
\GetProperty{\UndefinedPropertyList}{name}{DATA NOT AVAILABLE}
\bigskip%\newpage

Now change some things:
\bigskip

\verb|\SetProperty{\myNicePropertyList}{street}{11 Xample Lane}|:\\
\SetProperty{\myNicePropertyList}{street}{11 Xample Lane}
\texttt{\string\myNicePropertyList: \meaning\myNicePropertyList}
\bigskip

\verb|\SetProperty{\myNicePropertyList}{location}{Xample Junction}|:\\
\SetProperty{\myNicePropertyList}{location}{Xample Junction}
\texttt{\string\myNicePropertyList: \meaning\myNicePropertyList}
\bigskip

\verb|\SetProperty{\myNicePropertyList}{postal code}{NE2F 8KC}|:\\
\SetProperty{\myNicePropertyList}{postal code}{NE2F 8KC}
\texttt{\string\myNicePropertyList: \meaning\myNicePropertyList}
\vfill

\verb|\GetProperty{\myNicePropertyList}{street}{DATA NOT AVAILABLE}|:
\GetProperty{\myNicePropertyList}{street}{DATA NOT AVAILABLE}
\smallskip

\verb|\GetProperty{\myNicePropertyList}{location}{DATA NOT AVAILABLE}|:
\GetProperty{\myNicePropertyList}{location}{DATA NOT AVAILABLE}
\smallskip

\verb|\GetProperty{\myNicePropertyList}{postal code}{DATA NOT AVAILABLE}|:
\GetProperty{\myNicePropertyList}{postal code}{DATA NOT AVAILABLE}
\vfill

\end{document}

在此处输入图片描述

相关内容