3

Some latex that is autogenerated by Mathematica has this in it \text{Subst} as part of much longer latex.

Is there a way to write a macro to replace \text{Subst} with \operatorname{Subst} that I can put in the preamble? I do not know how to use \renewcommand to do this. It will be exactly \text{Subst} and nothing else that I want changed. i.e. no other \text{stuff}.

The reason I want to change it, is that it looks little better as an operator. There are so many of these in many files, so using the editor is not practical.

I can change in in Mathematica itself using string replacements pattern, but I thought it will be better to use Latex macro if possible.

MWE

\documentclass[12pt]{article}
\usepackage{amsmath}
\begin{document}

%\renewcommand{\text{Subst}}{\operatorname{Subst}}%does not work
\begin{align*} 
y &= -2 \text{Subst}\left(\int \frac{1}{(3+x)^2} \, dx,x\right)
\end{align*}

%want the above to become as follows

\begin{align*} 
y &= -2 \operatorname{Subst}\left(\int \frac{1}{(3+x)^2} \, dx,x\right)
\end{align*}

\end{document}

I looked at few questions, but could not figure how to do it.

TL 2020

Nasser
  • 20,220
  • 3
    Mathematica has TeXForm for that. It is IMHO much easier to tell Mathematica to make this an \operatorname when you export it from Mathematica. In general, TeXForm can really greatly help avoiding headache. (My head aches because of the italic differential d. Please use \mathrm{d}x.) –  May 10 '20 at 07:52
  • @Schrödinger'scat Yes, I know I could do it in Mathematica. This is output of TeXForm already. But I do not know how to tell TeXForm to only change this specific case to operatorname. I do not want to change all \text{...} to \operatorname{...}, only this one. But I can still do it in mathematica, using string change if needed. Just thought Latex macros can also do this, but was not sure. – Nasser May 10 '20 at 07:56
  • 2
    In general LaTeX is comparably bad at arbitrary string manipulation (in particular outside the scope of a suitable macro). I guess you could use LuaTeX to replace occurrences of \text{Subst} on the fly or you could redefine \text in a way that makes \text auto-detect if its argument is Subst and switch to \operatorname in that case. But it is not clear whether those two options would be acceptable for you (not everyone wants to use LuaTeX; the \text auto-detection sounds like a bad hack). I think the best way is to tell Mathematica to produce the right TeX code. – moewe May 10 '20 at 08:00
  • @moewe so in Latex, the command \renewcommand is only to change the command name to another name, and not to to change \command{agument} to another \command{argument}. In this case, no problem, I can easily change it in Mathematica before writing it to file with string replace command. Thanks. – Nasser May 10 '20 at 08:03
  • I think the Mathematica community has a solution here. It does yield \operatorname commands. I agree with @moewe. –  May 10 '20 at 08:18
  • @Nasser You could use etoolbox's \ifstrequal inside a redefinition of \text, but as others said, this sounds ugly (this wouldn't work if \text is redefined by amsmath environment mid-document, but I doubt this is the case). This way would not require LuaTeX. – frougon May 10 '20 at 08:32
  • 3
    To be honest. I think hacking \text is not at all a good idea. If you really want all occurrences of \text{Subst} to become \operatorname{Subst}, any text editor replaces this much faster than you copy any TeX solution in the document. Chances are you do not want to replace all of them and/or the TeX solution breaks (for instance because the arXiv has another version of expl3, say). Or one of you collaborators has the same great idea of also hacking \text, and the hacks clash. Let just Mathematica do it, much better. –  May 10 '20 at 08:45
  • I'm not quite sure if I understand correctly. \renewcommand redefines what the macro does with its argument. It is possible to check 'string equality' with the input, so you could in theory redefine \text to branch behaviour on whether or not the input is Subst. But that has a few caveats that have to do with how TeX handles text/strings. – moewe May 10 '20 at 08:47
  • thanks to everyone for the good answers. – Nasser May 10 '20 at 20:09

4 Answers4

6

It would be much better if the code has the proper markup, not relying on fragile post-processing.

However, since \operatorname only accepts “safe” characters (no accents unless a Unicode engine is used) you can get away by redefining \text.

I also use expl3 so the string-switch functions are already available.

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}
\usepackage{letltxmacro}

% save the meaning of \text
\LetLtxMacro{\AMStext}{\text}

% now redefine \text
\ExplSyntaxOn

\RenewDocumentCommand{\text}{m}
 {
  \str_case:nnF { #1 }
   {
    {Subst}{\operatorname{Subst}}
    {Foo}{\operatorname{\mathbf{Foo}}}
    % ...
   }
   {\AMStext{#1}}
 }
\ExplSyntaxOff

\begin{document}

\itshape

This is an operator $x\text{Subst}(y)$

This is also an operator $y\text{Foo}$

This is text $a\text{baz}$

\end{document}

enter image description here

egreg
  • 1,121,712
  • What if you work on a joint project and your collaborators have independently the idea of hacking an as basic command as \text? –  May 10 '20 at 08:48
  • @Schrödinger'scat Well, one of the collaborators has to yield. Reread my first paragraph, please. – egreg May 10 '20 at 08:51
  • 4
    Just for the records: I have seen such hacks going terribly wrong. I most strongly recommend not to hack basic commands. All one has to do is to do a trivial search and replace on the editor to have the same effect. –  May 10 '20 at 08:53
4

If you cannot get Mathematica to output \operatorname{Subst} instead of \text{Subst} and if you're free to use LuaLaTeX, the following solution may be of interest to you. It performs pattern matches and replaces all instances of \text{Subst} in the input file with \operatorname{Subst} "on the fly". The substitution operation is assigned to LuaTeX's process_input_buffer callback and therefore operates before TeX starts its usual processing operations (such as macro expansion). Observe that the \text macro is not redefined or modifed in any way.

I would further like to suggest that you load the mleftright package and use \mleft and \mright instead of \left and \right. This will improve (viz., reduce) the amount of whitespace between "Subst" and the large opening parenthesis.

enter image description here

\documentclass[12pt]{article}
\usepackage{amsmath,mleftright}
\usepackage{luacode} % for '\luaexec' macro
\luaexec{
function Subst ( s )
  return (s:gsub ( "\\text{Subst}" , "\\operatorname{Subst}" ))
end
luatexbase.add_to_callback("process_input_buffer", Subst , "Subst" ) 
}

\begin{document}
\begin{align*} 
y &= -2 \text{Subst}\mleft(\int \frac{1}{(3+x)^2} \, dx,x\mright) \\
  &= -2 \operatorname{Subst}\mleft(\int \frac{1}{(3+x)^2} \, dx,x\mright)
\end{align*}
\end{document}
Mico
  • 506,678
4

I recommend to have Mathematica not write \text or \operatorname but write some "placeholder-control-sequence" which in LaTeX and in packages used by many usually is not defined. This way you are free to define that placeholder-control-sequence in the preamble/wherever according to your liking without the need of overriding/overloading/redefining control-sequences that are already defined/in use for whatever purposes where they should not be redefined.

Be that as it may:

You can patch the \text-command to check whether its argument consists exactly of the token-sequence S11, u11, b11, s11, t11.

As \text is defined "robust" you actually need to patch the command whose name is \text⟨space⟩.

In the example below the check is implemented by means of a macro which processes delimited arguments rather than by defining temporary macros and doing \ifx-comparison. This way you don't have LaTeX (re)define temporary macros whenever \text is carried out. This in turn might save some of LaTeX's memory when \text is used more often.

With the delimited argument the phrase passed in as argument by the user is nested between exclamation-marks (!)/between something that does not occur within the phrase Subst. Then checking is done on the phrase !Subst!. This way you can crank out the case of the phrase passed in as argument by the user containing ! (and thus differing from the phrase Subst) before doing the checking by means of a !Subst!-delimited argument. Cranking out this case is needed in order to ensure that the phrase passed in as argument by the user does not consist of a set of tokens differing from the delimiter !Subst! but nevertheless containing and therefore matching that delimiter.

\documentclass[12pt]{article}
\usepackage{amsmath}
\makeatletter
%%-----------------------------------------------------------------------------
%% 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>}%
%%
%% This macro is explained in detail in:
%% <https://tex.stackexchange.com/a/522506/118714>
%% (The name given to it in that explanation is \CheckWhetherEmpty.)
%%
%% 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}%
}%
%%-----------------------------------------------------------------------------
\@ifdefinable\UD@GobbleToExclam{\long\def\UD@GobbleToExclam#1!{}}%
%%-----------------------------------------------------------------------------
\@ifdefinable\UD@SubstFork{%
  \long\def\UD@SubstFork#1!Subst!#2#3!!!!{#2}%
}%
\newcommand\UD@CheckWhetherSubst[3]{%
  \romannumeral0%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@GobbleToExclam#1!}{%
    \UD@SubstFork
    !#1!{ #2}% Case: #1 = Subst
    !Subst!{ #3}% Case: #1 is empty or something else without ! 
    !!!!%
  }{ #3}% Case: #1 is something else with ! 
}%
%%-----------------------------------------------------------------------------
%% Patch the command \text:
%% \text is robust, so actually the command \text<space> needs to be patched.
%%-----------------------------------------------------------------------------
\@ifdefinable\UD@Saved@Command@text{%
  \expandafter\let\expandafter\UD@Saved@Command@text\expandafter=\csname text \endcsname
}%
\long\@namedef{text }#1{%
  \UD@CheckWhetherSubst{#1}{\operatorname}{\UD@Saved@Command@text}{#1}%
}%
\makeatother

\begin{document}

\begin{align*} 
y &= -2 \text{Subst}\left(\int \frac{1}{(3+x)^2} \, dx,x\right)\\
  &= -2 \operatorname{Subst}\left(\int \frac{1}{(3+x)^2} \, dx,x\right)\\
  &\operatorname{Subst}&(\text{produced by {\tt\string\operatorname\{Subst\}}})\\
  &\text{Subst}&(\text{{\tt\string\operatorname}-variant produced by {\tt\string\text\{Subst\}}})\\
  &\text{Subst\empty}&(\text{{\tt\string\text}-variant produced by {\tt\string\text\{Subst\string\empty\}}})\\
  &\text{!Subst!}\\
  &\text{SubstSubst}\\
  &\text{Some bla bla}
\end{align*}


\end{document}

enter image description here

Ulrich Diez
  • 28,770
2

You can save the original meaning of \text to \origtext and then define \text as a macro which tests its argument if it is the "Subst":

\let\origtext=\text
\def\Subst{Subst}
\protected\def\text#1{\def\tmp{#1}\ifx\tmp\Subst 
   \expandafter \operatorname \else \expandafter \origtext \fi{#1}}
wipet
  • 74,238
  • Try to see what happens if you happen to have \section{$\text{Subst}$}. – egreg May 10 '20 at 16:26
  • @wipet Let me say that with the original definition $\text{\def\tempa#1{Text#1}\tempa{phrase}}$ does not yield ! Illegal parameter number in definition of \tmp. ;-) But I would consider this less of a daily-usage-problem and more of a moot thing :-) . Perhaps \edef\tmp{\unexpanded{#1}} instead of \def\tmp{#1}... – Ulrich Diez May 10 '20 at 20:46
  • @UlrichDiez Maybe, more robust should be \edef\Subst{\detokenized{Subst}} and \edef\tmp{\detokenized{#1}} because we don't know the catcode value of S (for example) when \text{Subst} is scanned from the file. But I keep simple solution in my answer. – wipet May 11 '20 at 04:25
  • @egreg I am surprised that LaTeX 2020 does not use immediately expanded section mark (like 2.4), asynchronusly expanded \the\pageno and most important: \unexpanded or \detokenized title when it is writing to the aux file. Is is still fiddling with \protect context-dependent macro and control sequences finished by space in its name? How long we have \unexpanded and \detokenized TeX primitives? – wipet May 11 '20 at 04:33
  • @Wipet On the other hand: Does a user who , e.g., switches catcode of S to 1 and catcode of t to 2 really want her/his user-input Subst to be considered equal to the textual-phrase Subst rather than equal to something like {ubs}? `;-) To be honest: I don't see a silver bullet for handling all edge cases, therefore: Yes, the simpler the solution, the better. I mentioned the problem with user-input containing temporary definitions with arguments/hashes because - regardless considerations of catcodes etc - hashes/defining temporary macros is possible with the original definition. – Ulrich Diez May 11 '20 at 09:04