这是一个演示
\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)。然后我尝试制作彩色框。但是,我发现一旦我包含包xcolor
或tcolorbox
(如 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}