我想检测一个参数是否包含字母以外的内容。这是一个基本的使用示例(实际上,这将产生 2x2 行列式的展开)。
\documentclass[12pt]{article}
\newcommand\doubleit[1]{%
2\,#1%
}
\begin{document}
\doubleit{x} % --> 2 x [OUTPUT EXPECTED]
\doubleit{-x} % --> 2(-x) [OUTPUT EXPECTED]
\doubleit{x-3} % --> 2(x - 3) [OUTPUT EXPECTED]
\end{document}
答案1
很自然地,用正则表达式检查:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\doubleit}{m}
{
\projetmbc_doubleit:n { #1 }
}
\prg_generate_conditional_variant:Nnn \regex_match:nn { nV } { T,F,TF }
\cs_new_protected:Nn \projetmbc_doubleit:n
{
\tl_set:Nn \l_tmpa_tl { #1 }
% get rid of spaces
\regex_replace_all:nnN { \s } { } \l_tmpa_tl
\regex_match:nVTF { .. } \l_tmpa_tl
{% more than one token
\regex_match:nVTF { \A -[0-9]* \Z } \l_tmpa_tl
{% we have a negative number
\int_eval:n { 2 * (\l_tmpa_tl) }
}
{
2(\l_tmpa_tl)
}
}
{% one token
\regex_match:nVTF { [0-9] } \l_tmpa_tl
{% it's a single digit number
\int_eval:n { 2 * \l_tmpa_tl }
}
{%
2\l_tmpa_tl
}
}
}
\ExplSyntaxOff
\begin{document}
$\doubleit{3}$
$\doubleit{-3}$
$\doubleit{x}$
$\doubleit{-x}$
$\doubleit{x-3}$
\end{document}
如果需要,可以在中间情况下添加\,
,但没有理由这样做。
答案2
这是一个基于 LuaLaTeX 的解决方案。如果 的参数\doubleit
——比如说x
——是一个数字,则直接将其乘以 2;如果是单个大写或小写字母,则输出为2x
;在所有其他情况下,输出为2(x)
。(如果x
由一个既不是字母也不是数字的字符组成,则不会返回任何内容,因为我们可能正在处理拼写错误……)
\documentclass{article}
\usepackage{luacode} % for "\luaexec" macro
\luaexec{ % Set up a Lua function:
function doubleit ( s )
if string.len ( s ) == 1 then
if s:find ( "\%d" ) then % it's a number!
tex.sprint ( 2*tonumber(s) )
elseif s:find ( "\%a" ) then % it's a letter!
tex.sprint ( "2" .. s )
end % do nothing if neither number nor letter
else
tex.sprint ( "2(" .. s .. ")" )
end
end
}
% Create a LaTeX "wrapper" macro:
\newcommand\doubleit[1]{\directlua{doubleit("#1")}}
\begin{document}
$\doubleit{x} \quad
\doubleit{3} \quad
\doubleit{-x} \quad
\doubleit{x-3} \quad
\doubleit{.}$
\end{document}
答案3
问题中并没有真正指定单个标记是数字的情况。我喜欢egreg 的方法实际上翻倍了,但从字面上理解这个问题,我们可以这样说
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\doubleit}{m}
{
\projetmbc_doubleit:n { #1 }
}
\cs_new_protected:Nn \projetmbc_doubleit:n
{
2
\bool_lazy_and:nnTF
{ \tl_if_single_token_p:n {#1} }
{ \token_if_letter_p:N #1 }
{#1}
{ (#1) }
}
\ExplSyntaxOff
\begin{document}
$\doubleit{3}$
$\doubleit{-3}$
$\doubleit{x}$
$\doubleit{-x}$
$\doubleit{x-3}$
\end{document}
答案4
这是一种检查每个标记的方法,以搜索范围 `A 到 `Z` 和 `a 到 `z` 之外的内容。
在当前实现中,宏被传递而不会影响决策。这也很容易改变。
\documentclass[12pt]{article}
\usepackage{tokcycle}
\newif\ifnonletter
\newcommand\doubleit[1]{%
\nonletterfalse%
\tokcycle{\tctestifnum{`##1>`@}
{\tctestifnum{`##1<`[}{}
{\tctestifnum{`##1>`\`}{}
{\tctestifnum{`##1<123}{}
{\nonlettertrue}}
{\nonlettertrue}}
{\nonlettertrue}}
{\nonlettertrue}}
{\processtoks{##1}}{}{}{#1}%
2\,\tctestifcon{\ifnonletter}{(#1)}{#1}%
}
\begin{document}
$\doubleit{x}$ % --> 2 x [OUTPUT EXPECTED]
$\doubleit{xy}$ % --> 2 xy [OUTPUT EXPECTED]
$\doubleit{-x}$ % --> 2(-x) [OUTPUT EXPECTED]
$\doubleit{x-3}$ % --> 2(x - 3) [OUTPUT EXPECTED]
$\doubleit{x/y}$ % --> 2(x/y) [OUTPUT EXPECTED]