\somecmd 和 \csname somecmd\endcsname 之间有什么区别?

\somecmd 和 \csname somecmd\endcsname 之间有什么区别?

这是一个演示

\documentclass{article}
\usepackage{soul}
\makeatletter
\newcommand{\mydef}[2]{%
    \expandafter\def\csname my#1\endcsname {#2}
}
\newcommand{\mygetdef}[1]{%
    \ifcsname my#1\endcsname \csname my#1\endcsname \else #1 not defined \fi%
}
\makeatother

\def\test{some text to complete}
\mydef{xxx}{some text to complete}

\begin{document}
\ul\test                 % it works
%%%% if uncomment, the below one does not work, an error is reported 
% \ul\mygetdef{xxx}
\end{document}

正如评论所说,如果\ul\mygetdef{xxx}发生,就会出现错误:

! \SOUL@@ 的参数有一个额外的 }。

更新:

我切换到可以下划线的包ulem\uline一切\fbox正常(参见下面的 MWE)。然后我尝试制作彩色框。但是,我发现一旦我包含包xcolortcolorbox(如 MWE 中的注释),甚至在我实际在文档中使用它们之前,就会立即出现一些奇怪的错误。

\documentclass{article}
%%% uncomment either of the packages below, it reports errors.
%\usepackage{xcolor}
%\usepackage{tcolorbox}

\usepackage[normalem]{ulem}
\makeatletter
\newcommand{\mydef}[2]{%
    \expandafter\def\csname my#1\endcsname {#2}
}
\newcommand{\mygetdef}[1]{%
    \ifcsname my#1\endcsname \csname my#1\endcsname \else \protect\fbox{#1} \fi%
}

\def\test{some text to complete}
\mydef{xxx}{some text to complete}

\begin{document}
\uline{\test}

\edef\mytmp{\mygetdef{xxx}}
\uline{\mytmp}

\edef\mytmp{\mygetdef{yyy}}
\uline{\mytmp}

\end{document}

经过我所有的努力,我还是无法找出原因并解决这个问题。所以我更新了我原来的问题。

答案1

尝试

\edef\tmp{\mygetdef{xxx}}
\ul\tmp

在传递给之前需要\mygetdef进行扩展\ul

\documentclass{article}
\usepackage{soul}
\makeatletter
\newcommand{\mydef}[2]{%
    \expandafter\def\csname my#1\endcsname {#2}
}
\newcommand{\mygetdef}[1]{%
    \ifcsname my#1\endcsname \csname my#1\endcsname \else #1 not defined \fi%
}
\makeatother

\def\test{some text to complete}
\mydef{xxx}{some text to complete}

\begin{document}
\ul\test                 % it works
%%%% if uncomment, the below one does not work, an error is reported 
% \ul\mygetdef{xxx}

\edef\tmp{\mygetdef{xxx}}
\ul\tmp
\end{document}

在此处输入图片描述


OP 补充说明

并不是真的要回答 OP 的问题,而是为了回复他对这个答案的一些评论:

\documentclass{article}
\usepackage{soul}
\makeatletter
\newcommand{\mydef}[2]{%
    \expandafter\def\csname my#1\endcsname {#2}
}
\newcommand{\mygetdef}[1]{%
    \ifcsname my#1\endcsname \csname my#1\endcsname \else
#1 not defined \fi%
}
\newcommand{\myulgetdef}[1]{%
    \ifcsname my#1\endcsname \expandafter\ul{\csname my#1\endcsname}%
  \else\fbox{#1 not defined} \fi%
}
\newcommand{\myxgetdef}[1]{%
    \ifcsname my#1\endcsname \expandafter\csname my#1\endcsname%
  \else\protect\protect\protect\fbox{#1 not defined} \fi%
}
\newcommand\exul[1]{\edef\tmp{#1}\ul\tmp}
\makeatother

\def\test{some text to complete}
\mydef{xxx}{some text to complete}

\begin{document}
\ul\test                 % it works

\exul{\mygetdef{xxx}}

1. \mygetdef{yyy}

2. \myulgetdef{yyy}

3. \myxgetdef{yyy}

4. \exul{\mygetdef{yyy}}

5. \exul{\myxgetdef{yyy}}% HOWEVER, \fbox IS NOT UNDERLINED

%6. \exul{\myulgetdef{yyy}}% FAILS; CANNOT \ul{\fbox{...}}

\end{document}

在此处输入图片描述

答案2

命令\ul定义为\SOUL@ulsetup\SOUL@。第一个命令设置了一些命令,这些命令将在组启动后稍后传递,这里与此无关。

\SOUL@定义为

% soul.sty, line 99:
\def\SOUL@{%
    \futurelet\SOUL@@\SOUL@expand
}

这意味着查找以下标记并将其存储在\SOUL@@; 然后\SOUL@expand执行

% soul.sty, line 102:
\def\SOUL@expand{%
    \ifcat\bgroup\noexpand\SOUL@@
        \let\SOUL@n\SOUL@start
    \else
        \bgroup
            \def\\##1##2{\def##2{\noexpand##2}}%
            \the\SOUL@cmds
            \SOUL@buffer={%
                \\\TeX\\\LaTeX\\\soulomit\\\mbox\\\hbox\\\textregistered
                \\\slash\\\textcircled\\\copyright\\\S\\\,\\\<\\\>\\~%
                \\\\%
            }%
            \def\\##1{\def##1{\noexpand##1}}%
            \the\SOUL@buffer
            \let\protect\noexpand
            \xdef\SOUL@n##1{\noexpand\SOUL@start{\SOUL@@}}%
        \egroup
    \fi
    \SOUL@n
}

真是拗口!行为取决于存储在中的标记是否\SOUL@@是左括号。您的情况并非如此。

上面代码中最令人感兴趣的部分是

            \let\protect\noexpand
            \xdef\SOUL@n##1{\noexpand\SOUL@start{\SOUL@@}}%

请注意,\SOUL@@在您的情况下,是在第一步中找到的令牌\mygetdef。最后,\SOUL@n执行,它会丢弃下一个令牌(您的\mygetdef),然后执行

\SOUL@start{<full expansion of \mygetdef`>}

错误发生的地方是在\xdef,因为\mygetdef没有找到它的参数,而只是找到右括号。你想要的是

\ul\mygetdef{xxx}

变成

\ul\myxxx

你需要对此进行一些巧妙的扩展,但这会变得非常尴尬,主要是因为条件。如果你这样做

\expandafter\ul\myxxx

你得到

\ul\ifcsname myxxx\endcsname\csname myxxx\endcsname\else xxx not defined \fi

\expandafter三个

\ul\csname myxxx\endcsname\else xxx not defined \fi

\expandafter七个

\ul\myxxx\else xxx not defined \fi

就是这样!让我们看看会发生什么\mygetdef{noway}(假设它未定义)。你会得到

\ul noway not defined \fi

这不是您真正想要的,但可以轻松修复。

\documentclass{article}
\usepackage{soul}

\newcommand{\mydef}[2]{%
  \expandafter\def\csname my#1\endcsname{#2}
}
\newcommand{\mygetdef}[1]{%
  \ifcsname my#1\endcsname
    \csname my#1\endcsname
  \else
   {}#1 not defined%
  \fi
}

\def\test{some text to complete}
\mydef{xxx}{some text to complete}

\begin{document}

\ul\test

\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter
\expandafter\ul\mygetdef{xxx}

\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter
\expandafter\ul\mygetdef{noway}

\end{document}

在此处输入图片描述

\mygetdef我的建议是,如果您打算在宏之后使用它,则进行不同的定义soul,但不仅限于此。

\documentclass{article}
\usepackage{soul}

\makeatletter
\newcommand{\mydef}[2]{%
  \@namedef{my#1}{#2}
}
\newcommand{\mygetdef}[2][\relax]{%
  \@ifundefined{my#2}%
    {{}#2 not defined}%
    {\expandafter#1\csname my#2\endcsname}%
}
\makeatother

\mydef{xxx}{some text to complete}

\begin{document}

\mygetdef{xxx}

\mygetdef[\ul]{xxx}

\mygetdef[\textit]{xxx}

\mygetdef[\ul]{noway}

\end{document}

在此处输入图片描述

相关内容