自动为 \cos, \sin, \log, ecc. 添加括号,允许下标

自动为 \cos, \sin, \log, ecc. 添加括号,允许下标

如果标题暗示了一个已经被问过很多次的问题(见下文),我很抱歉,但我找不到既能满足其他需求的答案......

作为一名数学老师,我希望我的学生(至少在开始时)习惯于在 cos、sin、tan、log、ln 等函数周围写上括号,这样 cos(x) 而不是 cos x。因此,我希望我的 LaTeX 文件始终自动将这些函数放在 (...) 周围,通过将它们称为 \cos{x} 来调用它们。

为此,我已经找到了多个可以让我实现这一目标的问题/答案,例如

我从第一个链接中选择了以下版本:

\makeatletter
\newcommand*{\redefinesymbolwitharg}[1]{%
  \expandafter\let\csname ltx#1\expandafter\endcsname\csname #1\endcsname
  \@namedef{#1}{\@ifnextchar{^}{\@nameuse{#1@}}{\@nameuse{#1@}^{}}}%
  \expandafter\def\csname #1@\endcsname^##1##2{%
     \csname ltx#1\endcsname\ifx!##1!\else^{##1}\fi\mathopen{}\mathclose\bgroup\left(##2\aftergroup\egroup\right)
     }%
}
\makeatother

然后调用例如

\redefinesymbolwitharg{cos}

上面的代码允许我编写

\cos x + \cos{y} + \cos^{2}{z} + \cos^3{k}

总是在参数周围添加括号,但不要写

\cos_a{x}

尝试理解上述代码,我发现 @ifnextchar{^} 情况是经过专门处理的,但我无法集成“_”情况,例如 \log 函数所必需的情况。有人能帮我将此功能添加到上述代码中吗(或者建议另一种实现方式?)。

提前感谢您的任何建议!:)


附加问题:

是否也可以将 \cos'{x} 的情况整合到 \cos^{'}{x} 中,对于 ' ' 和 ' ' ' 也是如此?这不是强制性的,但可以改善很多行的编写...

答案1

你说:

作为一名数学老师,我希望我的学生习惯(至少在开始时)在 cos、sin、tan、log、ln 等函数周围写上括号。

... 而看起来你自己希望习惯在你的 .tex-input-files 中根本不需要这样做。;-)

顺便一提:

您到底想让学生在括号里写什么?
指定相关函数(名称)的字符序列?
指定函数操作数/参数的字符序列?
在向学习者灌输新知识时,请做到准确无误。

\cos,,,,,是不处理参数的宏\sin,因为它们用于排版指定\tan相关函数(名称)的字符序列。\log\ln

使用$\cos$(La)TeX 可以很好地排版短语“cos”。

使用$\cos{x}$(La)TeX 可以很好地排版短语“cos”。然后{x}处理该序列,生成数学字体中的字母x。数学模式中的花括号可以防止嵌套在其中的内容导致换行。因此在这种情况下,它们不是必需的,因为它们之间只嵌套了一个字符,这使得考虑换行变得毫无意义。 (如果我在这里错了/忽略了某些东西,请给我提示,我会立即纠正我的答案。)

您实际上要求一种能够自动检测所讨论函数的参数/操作数的机制。(←越进一步。)
您可能还需要一种能够自动检测下标/上标是否放在括号之间的机制。(我认为在下标/上标包含除单个数字或单个变量以外的其他内容的情况下应该这样做。)(←后者。

在下面的例子中我没有尝试实现后者。

我只是尽力去实现进一步的目标。

我通过基于\@ifnextchar的递归循环来实现这一点,该循环会收集事物,直到找到其含义既不等于_也不等于^也不等于 的标记'。只要您不做类似的事情\cos\empty\relax{(x)},这可能就足够了。

\documentclass[landscape, oneside]{article}
%===================[adjust margins/layout for the example]====================
\csname @ifundefined\endcsname{pagewidth}{}{\pagewidth=\paperwidth}%
\csname @ifundefined\endcsname{pdfpagewidth}{}{\pdfpagewidth=\paperwidth}%
\csname @ifundefined\endcsname{pageheight}{}{\pageheight=\paperheight}%
\csname @ifundefined\endcsname{pdfpageheight}{}{\pdfpageheight=\paperheight}%
\textwidth=\paperwidth
\oddsidemargin=1.25cm
\marginparsep=.2\oddsidemargin
\marginparwidth=\oddsidemargin
\advance\marginparwidth-2\marginparsep
\advance\textwidth-2\oddsidemargin
\advance\oddsidemargin-1in
\evensidemargin=\oddsidemargin
\textheight=\paperheight
\topmargin=1.25cm
\footskip=.5\topmargin
{\normalfont\global\advance\footskip.5\ht\strutbox}%
\advance\textheight-2\topmargin
\advance\topmargin-1in
\headheight=0ex
\headsep=0ex
\pagestyle{plain}
\parindent=0ex
\parskip=0ex 
\topsep=0ex
\partopsep=0ex
%==================[eof margin-adjustments]====================================

\makeatletter

\newcommand\gatherargumentloop[1]{%
  % #1 - amount of arguments/operands to gather.
  % Let's create an amount of catcode-12-characters "m" equal to the amount of
  % arguments to gather.
  \expandafter\@gatherargumentloop\expandafter{\romannumeral\number\number#1 000}%
}%
\newcommand\@gatherargumentloop[1]{%
  \if\relax#1\relax\expandafter\@gobble\else\expandafter\@firstofone\fi
  {%
    \@ifnextchar^{\gathersupscript{#1}}{%
      \@ifnextchar_{\gathersubscript{#1}}{%
        \@ifnextchar'{\gatherprimesloop{#1}{}}{%
          \gatherargument{#1}%
        }%
      }%
    }%
  }%
}%
\@ifdefinable\gatherprimesloop{%
  \long\def\gatherprimesloop#1#2'{%
    \@ifnextchar'{\gatherprimesloop{#1}{#2'}}{{#2'}\@gatherargumentloop{#1}}%
  }%
}%
\@ifdefinable\gathersupscript{%
  \long\def\gathersupscript#1^#2{%
     ^{#2}\@gatherargumentloop{#1}%
  }%
}%
\@ifdefinable\gathersubscript{%
  \long\def\gathersubscript#1_#2{%
     _{#2}\@gatherargumentloop{#1}%
  }%
}%
\newcommand\gatherargument[1]{%
  \@ifnextchar({\@@gatherargument{#1}}{\@gatherargument{#1}}%
}%
\newcommand\@gatherargument[2]{%
  \UD@CheckWhetherLeadingTokens{#2}{\left(}{.}{\LeftLeftParen}{#2}{%
    \UD@CheckWhetherLeadingTokens{#2}{(}{.}{\LeftParen}{#2}{%
      \UD@CheckWhetherLeadingTokens{#2}{ (}{.}{\SpaceLeftParen}{#2}{%
        \UD@CheckWhetherLeadingTokens{#2}{ \left(}{.}{\SpaceLeftLeftParen}{#2}{%
          (#2)%
        }%
      }%
    }%
  }% 
  \expandafter\@gatherargumentloop\expandafter{\@gobble#1}%
}%
\@ifdefinable\@@gatherargument{%
  \long\def\@@gatherargument#1#2){%
    #2)%
    \expandafter\@gatherargumentloop\expandafter{\@gobble#1}%
  }%
}%
%==========[code for checking leading token-sequences in arguments]============
%% 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>
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral0\expandafter\@secondoftwo\string{\expandafter
  \@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
  \@secondoftwo\string}\@firstoftwo\expandafter{} \@secondoftwo}%
  {\@firstoftwo\expandafter{} \@firstoftwo}%
}%
%
%%-----------------------------------------------------------------------------
%% Exchange two arguments. (From each argument an outermost level of 
%% surrounding braces will be removed if present.)
%%-----------------------------------------------------------------------------
\newcommand\UD@Exchange[2]{#2#1}%
%%-----------------------------------------------------------------------------
%% Check whether argument's leading tokens form a specific 
%% token-sequence that does not contain explicit character tokens of 
%% category code 1 or 2:
%%.............................................................................
%% \UD@CheckWhetherLeadingTokens{<argument which is to be checked>}%
%%                              {<a <token sequence> without explicit 
%%                                character tokens of category code
%%                                1 or 2>}%
%%                              {a <single non-space token> that does 
%%                                _not_ occur in <token sequence> >}%
%%                              {<internal token-check-macro>}%
%%                              {<tokens to be delivered in case
%%                                <argument which is to be checked> has
%%                                <token sequence> as leading tokens>}%
%%                              {<tokens to be delivered in case 
%%                                <argument which is to be checked>
%%                                does not have <token sequence> as
%%                                leading tokens>}%
\newcommand\UD@CheckWhetherLeadingTokens[4]{%
  \romannumeral0\UD@CheckWhetherNull{#1}%
  {\UD@Exchange{ }\expandafter\@secondoftwo}%
  {\expandafter\@secondoftwo\string{\expandafter
   \UD@@CheckWhetherLeadingTokens#4#3#1#2}{}}%
}%
\newcommand\UD@@CheckWhetherLeadingTokens[1]{%
  \expandafter\UD@CheckWhetherNull\expandafter{\@firstoftwo{}#1}%
  {\UD@Exchange{\@firstoftwo}}{\UD@Exchange{\@secondoftwo}}%
  {\UD@Exchange{ }{\expandafter\expandafter\expandafter\expandafter
   \expandafter\expandafter\expandafter}\expandafter\expandafter
   \expandafter}\expandafter\@secondoftwo\expandafter{\string}%
}%
%%-----------------------------------------------------------------------------
%% \UD@internaltokencheckdefiner{<internal token-check-macro>}%
%%                              {<token sequence>}%
%% Defines <internal token-check-macro> to snap everything 
%% until reaching <token sequence>-sequence and spit that out
%% nested in braces.
%%-----------------------------------------------------------------------------
\newcommand\UD@internaltokencheckdefiner[2]{%
  \@ifdefinable#1{\long\def#1##1#2{{##1}}}%
}%
\UD@internaltokencheckdefiner{\LeftLeftParen}{\left(}%
\UD@internaltokencheckdefiner{\LeftParen}{(}%
\UD@internaltokencheckdefiner{\SpaceLeftParen}{ (}%
\UD@internaltokencheckdefiner{\SpaceLeftLeftParen}{ \left(}%
%=======[end ofcode for checking leading token-sequences in arguments]=========

\makeatother

\newcommand\mycos{\cos\gatherargumentloop{1}}
\newcommand\mysin{\sin\gatherargumentloop{1}}
\newcommand\mytan{\tan\gatherargumentloop{1}}
\newcommand\mycot{\cot\gatherargumentloop{1}}
\newcommand\mylog{\log\gatherargumentloop{1}}
\newcommand\myln{\ln\gatherargumentloop{1}}

% Like \cos, \sin, \tan, \log, \ln, but with two operands:
\makeatletter
\newcommand\add{\mathop{\operator@font add}\nolimits}%
\makeatother

\newcommand\myadd{\add\gatherargumentloop{2}}

\begin{document}

The $\cos$-game:

\medskip

{\footnotesize\verb|$\mycos x + \mycos{y} + \mycos^{2+3}{z} + \mycos^3{k} + \mycos_{a_1}{x} + \mycos'''''_{a_1}{x} +  \mycos'''''_{a_1}(x) + \mycos'''''_{a_1}{(x)}$|:}

$\mycos x + \mycos{y} + \mycos^{2+3}{z} + \mycos^3{k} + \mycos_{a_1}{x} + \mycos'''''_{a_1}{x} +  \mycos'''''_{a_1}(x) + \mycos'''''_{a_1}{(x)}$

\bigskip

The $\sin$-game:

\medskip

{\footnotesize\verb|$\mysin x + \mysin{y} + \mysin^{2+3}{z} + \mysin^3{k} + \mysin_{a_1}{x} + \mysin'''''_{a_1}{x} + \mysin'''''_{a_1}(x) + \mysin'''''_{a_1}{(x)}$|:}

$\mysin x + \mysin{y} + \mysin^{2+3}{z} + \mysin^3{k} + \mysin_{a_1}{x} + \mysin'''''_{a_1}{x} + \mysin'''''_{a_1}(x) + \mysin'''''_{a_1}{(x)}$

\bigskip

The $\tan$-game:

\medskip

{\footnotesize\verb|$\mytan x + \mytan{y} + \mytan^{2+3}{z} + \mytan^3{k} + \mytan_{a_1}{x} + \mytan'''''_{a_1}{x} + \mytan'''''_{a_1}(x) + \mytan'''''_{a_1}{(x)}$|:}

$\mytan x + \mytan{y} + \mytan^{2+3}{z} + \mytan^3{k} + \mytan_{a_1}{x} + \mytan'''''_{a_1}{x} + \mytan'''''_{a_1}(x) + \mytan'''''_{a_1}{(x)}$

\bigskip

The $\cot$-game:

\medskip

{\footnotesize\verb|$\mytan x + \mytan{y} + \mytan^{2+3}{z} + \mytan^3{k} + \mytan_{a_1}{x} + \mytan'''''_{a_1}{x} + \mytan'''''_{a_1}(x) + \mytan'''''_{a_1}{(x)}$|:}

$\mycot x + \mycot{y} + \mycot^{2+3}{z} + \mycot^3{k} + \mycot_{a_1}{x} + \mycot'''''_{a_1}{x} + \mycot'''''_{a_1}(x) + \mycot'''''_{a_1}{(x)}$

\bigskip

The $\log$-game:

\medskip

{\footnotesize\verb|$\mylog x + \mylog{y} + \mylog^{2+3}{z} + \mylog^3{k} + \mylog_{a_1}{x} + \mylog'''''_{a_1}{x} + \mylog'''''_{a_1}(x) + \mylog'''''_{a_1}{(x)}$|:}

$\mylog x + \mylog{y} + \mylog^{2+3}{z} + \mylog^3{k} + \mylog_{a_1}{x} + \mylog'''''_{a_1}{x} + \mylog'''''_{a_1}(x) + \mylog'''''_{a_1}{(x)}$

\bigskip

The $\ln$-game:

\medskip

{\footnotesize\verb|$\myln x + \myln{y} + \myln^{2+3}{z} + \myln^3{k} + \myln_{a_1}{x} + \myln'''''_{a_1}{x} + \myln'''''_{a_1}(x) + \myln'''''_{a_1}(x)$|:}

$\myln x + \myln{y} + \myln^{2+3}{z} + \myln^3{k} + \myln_{a_1}{x} + \myln'''''_{a_1}{x} + \myln'''''_{a_1}(x) + \myln'''''_{a_1}(x)$

\bigskip

The $\add$-game:

\medskip

{\footnotesize\verb|$\myadd xy + \myadd{x}{y} + \myadd^{2+3}{y}{z} + \myadd^3{k}{l} + \myadd_{a_1}{x}{y} + \myadd'''''_{a_1}{x}{y} + \myadd'''''_{a_1}(x)(y) + \myadd'''''_{a_1}{(x)}{(y)}$|:}

$\myadd xy + \myadd{x}{y} + \myadd^{2+3}{y}{z} + \myadd^3{k}{l} + \myadd_{a_1}{x}{y} + \myadd'''''_{a_1}{x}{y} + \myadd'''''_{a_1}(x)(y) + \myadd'''''_{a_1}{(x)}{(y)}$

\end{document}

在此处输入图片描述

答案2

这是一个基于 LuaLaTeX 的解决方案,适用于涉及\sin\cos\tan和 的表达式\cot。它们的参数可以是 1 个或多个字母(例如xxy),也可以\紧跟一个或多个字母,例如\theta\Omega。参数可以是独立的,也可以用花括号括起来。也可以是上标项,例如 、^2n(不确定一个理智的人是否会写出这个!)(3!)

代码由一个 Lua 函数组成,该函数add_parens完成所有工作,还有两个 LaTeX 宏,分别称为\AddParensOn\AddParensOff,用于激活和停用 Lua 函数。Lu​​a 函数执行许多单独的字符串替换操作,因为例如,必须将 和 都\sin x更改\sin {x}\sin(x)。当然,如果遇到 ,代码一定不能出错,\sin(x)即在这种情况下不必添加额外的括号。如果您可以限制输入文本以避免\sin{x},那么替换操作可以大大简化。

处理带有下标的表达式,例如\log_2 8\log_{10} 1000,留给读者作为练习。:-)

在此处输入图片描述

% !TEX TS-program = lualatex
\documentclass{scrreprt}
\usepackage{luacode}
%% The 'add_parens' Lua function does most of the work:
\begin{luacode}
function add_parens ( s )
  ll= { "sin" , "cos" , "tan" , "cot" }
  for i=1,#ll do
    s = s:gsub ( "(\\"..ll[i]..")%s+(%a+)"   , "%1(%2)" ) -- \sin x
    s = s:gsub ( "(\\"..ll[i]..")%s-(\\%a+)" , "%1(%2)" ) -- \cos\alpha
    s = s:gsub ( "(\\"..ll[i]..")%s-(%b{})"  , "%1(%2)" ) -- \tan{y}
    s = s:gsub ( "(\\"..ll[i]..")%s-(^%s-%w)%s-(\\?%a+)"  , "%1%2(%3)" ) -- \sin^2 z 
    s = s:gsub ( "(\\"..ll[i]..")%s-(^%s-%w)%s-(%b{})"    , "%1%2(%3)" ) -- \sin^3 {u}
    s = s:gsub ( "(\\"..ll[i]..")%s-(^%s-%b{})%s-(\\?%a+)", "%1%2(%3)" ) -- \cos ^{2} \pi
    s = s:gsub ( "(\\"..ll[i]..")%s-(^%s-%b{})%s-(%b{})"  , "%1%2(%3)" ) -- \cos ^{10} {v}
  end  
  return s
end
\end{luacode}

%% Define two "toggle switch" LaTeX macros:
\newcommand\AddParensOn{\directlua{ luatexbase.add_to_callback 
  ( "process_input_buffer" , add_parens , "AddParens" )}}
\newcommand\AddParensOff{\directlua{ luatexbase.remove_from_callback 
  ( "process_input_buffer" , "AddParens" )}}

\begin{document}
$\sin\alpha \cos {\gamma} \tan xy \sin{z} \cos^2x \cot ^ {(3!)} {\omega}$ 

\medskip
\AddParensOn % enable the Lua function
$\sin\alpha \cos {\gamma} \tan xy \sin{z} \cos^2x \cot ^ {(3!)} {\omega}$

%% make sure the function doesn't operate on terms with parens:
$\sin(\alpha) \cos (\gamma) \tan(xy) \sin(z) \cos ^2(x) \cot ^ {(3!)} (\omega)$

\medskip
\AddParensOff % disable the Lua function
$\sin\alpha \cos {\gamma} \tan xy \sin{z} \cos^2x \cot ^ {(3!)} {\omega}$
\end{document}

相关内容