![如何将宏参数扩展为字符串,删除所有空格,然后在 \NewDocumentCommand 宏定义中附加和添加字符串?](https://linux22.com/image/453151/%E5%A6%82%E4%BD%95%E5%B0%86%E5%AE%8F%E5%8F%82%E6%95%B0%E6%89%A9%E5%B1%95%E4%B8%BA%E5%AD%97%E7%AC%A6%E4%B8%B2%EF%BC%8C%E5%88%A0%E9%99%A4%E6%89%80%E6%9C%89%E7%A9%BA%E6%A0%BC%EF%BC%8C%E7%84%B6%E5%90%8E%E5%9C%A8%20%5CNewDocumentCommand%20%E5%AE%8F%E5%AE%9A%E4%B9%89%E4%B8%AD%E9%99%84%E5%8A%A0%E5%92%8C%E6%B7%BB%E5%8A%A0%E5%AD%97%E7%AC%A6%E4%B8%B2%EF%BC%9F.png)
我想将宏参数扩展为字符串,删除所有空格,然后在 \NewDocumentCommand 宏定义中附加和添加字符串。
这是我使用 LuaLaTeX 的 MWE。
\documentclass[oneside,DIV=12]{scrbook}
\usepackage{scrhack}
\usepackage{mathtools, amssymb}
\usepackage[warnings-off={mathtools-colon,mathtools-overbracket}]{unicode-math}
\setmathfont{Latin Modern Math}
\usepackage{xparse}
\usepackage{xpatch}
% \ExpandArg (https://tex.stackexchange.com/a/515425)
\ExplSyntaxOn
\cs_new_protected:Nn \__user_expand_arg:n
{
\tl_set:No \ProcessedArgument { #1 }
}
\cs_set_eq:NN \ExpandArg \__user_expand_arg:n
\ExplSyntaxOff
% \RemoveSpaces (https://tex.stackexchange.com/a/87510)
\makeatletter
\def\RemoveSpaces#1{\zap@space#1 \@empty}
\makeatother
% \foo, \foobar, and \xy
\NewDocumentCommand{\foo}{>{\ExpandArg} m}{%
\renewcommand{\foobar}{+\RemoveSpaces{#1}.}
\xpatchcmd{\foobar}{+x-y.}{++xx--yy..}{}{} % check if there's a '+x-y.' w/o any spaces, then replace it with '++xx--yy..'
\foobar % print the output
}
\newcommand{\foobar}{}
\newcommand{\xy}{ x - y }
\begin{document}\KOMAoptions{DIV=current}\Large%
\[\foo{\xy}\] % if all the spaces are removed, it should print the output as '++xx--yy..' and not '+x-y.'
\end{document}
为什么这不起作用?我认为问题可能是我不太明白\RemoveSpaces
作品。
谢谢。
答案1
\zap@space
通过完全扩展起作用,因此必须在\edef
或\expanded
上下文中使用。您的\foobar
的内容不会在 内扩展\renewcommand
,因此它将与您在那里填写的内容完全相同。宏\xy
被扩展一次,留下␣x␣-␣y␣
,然后您将其分配给\foobar
,它将包含+\RemoveSpaces{␣x␣-␣y␣}.
现在与您的搜索字符串 不匹配的内容+x-y.
。
但请注意,它\zap@space
有几个历史限制:它必须在完全扩展上下文中使用,并且它可能会删除您想要保留的括号。
下面定义了一个参数处理器,它可以消除所有空间而不受这些限制,因此您可以#1
在其中简单地使用\renewcommand
。
\documentclass[oneside,DIV=12]{scrbook}
\usepackage{scrhack}
\usepackage{xparse}
\usepackage{xpatch}
% \ExpandArg (https://tex.stackexchange.com/a/515425)
\ExplSyntaxOn
\cs_new_protected:Nn \__user_expand_arg:n
{
\tl_set:No \ProcessedArgument { #1 }
}
\cs_set_eq:NN \ExpandArg \__user_expand_arg:n
\cs_new_protected:Npn \__user_arg_zap_spaces:n #1
{
\tl_set:Nn \ProcessedArgument {#1}
\tl_remove_all:Nn \ProcessedArgument { ~ }
}
\cs_set_eq:NN \ArgZapSpaces \__user_arg_zap_spaces:n
\ExplSyntaxOff
% \foo, \foobar, and \xy
\NewDocumentCommand{\foo}{>{\ArgZapSpaces}>{\ExpandArg} m}{%
\renewcommand{\foobar}{+#1.}
\xpatchcmd{\foobar}{+x-y.}{++xx--yy..}{}{} % check if there's a '+x-y.' w/o any spaces, then replace it with '++xx--yy..'
\foobar % print the output
}
\newcommand{\foobar}{}
\newcommand{\xy}{ x - y }
\begin{document}\KOMAoptions{DIV=current}\Large%
\[\foo{\xy}\] % if all the spaces are removed, it should print the output as '++xx--yy..' and not '+x-y.'
\end{document}
为了完整性,\zap@space
工作原理如下:
\zap@space
定义为
\def\zap@space#1 #2{#1\ifx#2\@empty\else\expandafter\zap@space\fi#2}
因此,它将所有内容读取到空格处#1
,并将其输出。此外,它还读取一个标记(或括号组,将由此取消括号)并将其与\@empty
(这是您的中的结束标记\RemoveSpaces
)进行比较。如果#2
不是,则调用\@empty
\zap@space
自身。#2
在末尾重新插入(如果是,它将\@empty
扩展为空,因此不会造成任何影响)。所采用的方法只能在完全扩展的情况下起作用,因为#1
总是在下一次调用之前放置\zap@space
,因此我们不能从左侧扩展直到\zap@space
完成(除了在无意义的情况下,#1
只会扩展为空)。