# Is there a way to convert \def macro in \newcommand macro automatically?

I have a big file of macros, they are all in this form :

\def\eclaire{\mathbb}
\def\R{\ensuremath{\eclaire R}}



\newcommand \eclaire{\mathbb}
\newcommand \R{\ensuremath{\eclaire R}}


But for some others macros like this one :

\def\rond#1{\build#1_{}^{\>\circ}}


I can't because the solution is :

\newcommand\rond[1]{\build#1_{}^{\>\circ}}


So my question is, is there a script that can transform my \def command into \newcommand automatically ?

• I forgot to ignore the # in the second group and you may want to catch things like \def\foo##1 as well. So \\def(\\[^{#]*)(?:#+([0-9]))* would probably be better. – moewe Mar 23 at 8:49
• Possibly relevant for the motivation: tex.stackexchange.com/q/475311/35864 – moewe Mar 23 at 11:19


\newenvironment{Cases}{%
\left\lbrace
\def\arraystretch{1.2}%
}{%
\endarray\right.%
}



\def\build#1_#2^#3{\mathrel{\mathop{\kern 0pt#1}\limits_{#2}^{#3}}} %CLENET



If we allow for these simplifications

s/\\def(\\[^{#]*)(?:#+([0-9]))*{/\\newcommand{$1}[0$2]{/g


yields acceptable results.

The following (crude approximation of a) Lua script does something quite similar. I didn't manage to get the matching for the argument structure #1, #1#2, ... done in a single group, so I opted for a loop doing that instead.

local io = require('io')
local string = string

local filename = arg[1] or nil

function newcommandify(content)
content = string.gsub(content, "\\def(\\[^{#]*){",
"\\newcommand{%1}{")
local iargs = ''
for i=1,9 do
iargs = iargs .. "#+" .. i
content = string.gsub(content, "\\def(\\[^{#]*)" .. iargs .. "{",
"\\newcommand{%1}[".. i .. "]{")
end
return content
end

if filename then
local file_handle = assert(io.open(filename, 'r'))
io.close(file_handle)

content = newcommandify(content)

file_handle = assert(io.open(filename .. "-newcommand", 'w'))
file_handle:write(content)
io.close(file_handle)
end


Save it as def-to-newcommand.lua and run

texlua def-to-newcommand.lua <yourfilename>



• the LUA script do not work for this  \def{\Sp}{\mathop{\rm Sp}\nolimits} \def{\spec}{\mathop{\rm sp}\nolimits} Do you know why ? – Evan Barberousse Mar 23 at 12:02
• @EvanBarberousse It doesn't catch those. You can catch them by additionally searching for "\\def{(\\[^{#]*)}{" and "\\def{(\\[^{#]*)}" .. iargs .. "{". – moewe Mar 23 at 12:13
• \def{\Sp} is bad syntax for \def. – wipet Mar 24 at 14:17

Why do you wish to transform assignments in terms of \def into assignments in terms of \newcommand?

If it is only about ensuring that macros that are already defined won't get overridden, you can do another approach:

Basically \newcommand behaves as follows:

It checks for a star and optional argument and applies the kernel-macro \@ifdefinable for finding out whether the control sequence token in question is already defined within the current scope.

If so, \@ifdefinable will throw an error-message and not (re)define the control sequence token in question.

If not so, the control-sequence-token in question will be defined in terms of \def (, probably preceded by \long). In case of processing optional arguments, routines for detecting the presence of an optional argument will be included into the definitions performed by \newcommand, also.

Caveats with \newcommand:




\let\MyCommand=\relax
% now \MyCommand is defined and its meaning equals the meaning of the \relax-primitive
\newcommand\MyCommand{This is the redefinition of MyCommand which gets carried out without warnings/error-messages.}


You can also do this within a local scope/within a group for causing \newcommand to take \MyCommand for undefined within that scope.

A caveat is: If you do something like

\begingroup
\let\MyCommand=\relax
% now \MyCommand is defined and its meaning equals the meaning of the \relax-primitive
\newcommand\MyCommand{This is the redefinition of MyCommand which gets carried out without warnings/error-messages.}
\global\let\MyCommand=\MyCommand
\endgroup


, \MyCommand might already have been defined outside the group and it will be overridden outside the group/within all scopes without whatsoever notification.

My suggested approach is:

Assignments in terms of \def are always of pattern

⟨prefix⟩\def⟨control sequence token⟩⟨parameter text⟩{⟨replacement text⟩}

, with ⟨prefix⟩ =emptiness or a combination of \global and/or \long and/or \outer.

(With \gdef or \edef or \xdef the pattern looks accordingly.)

You can implement a macro \definedchecker which via catching a left-brace-delimited argument (→see the TeXbook for #1#{-notation) gathers the ⟨prefix⟩, the \def, the ⟨control sequence token⟩ and the ⟨parameter text⟩ and then checks whether this contains \def or \gdef or \edef or \xdef and if so uses that information for splitting the ⟨prefix⟩, the \def, the ⟨control sequence token⟩ and the ⟨parameter text⟩ apart before applying \@ifdefinable—but be aware that the \@ifdefinable-check is not completely save when it is about defining a control sequence token not only within the current scope but globally.

In other words: You can implement a macro \definedchecker which is to be prepended to your \def/\gdef/\edef/\xdef-sequences and which checks whether the control sequence token in question is already defined within the current scope and if so delivers an error-message and if not so performs the assignment.
!!!Be aware that checking for a control sequence token being defined within the current scope is not completely safe when it comes to defining it globally!!!

% Compile this example by calling LaTeX from a shell/command-prompt/console
% where you can also see the messages of the program!
%
\documentclass{article}
\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>}%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral0\expandafter\@secondoftwo\string{\expandafter
\@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
\@secondoftwo\string}\expandafter\expandafter\@firstoftwo{ }{}%
\@secondoftwo}{\expandafter\expandafter\@firstoftwo{ }{}\@firstoftwo}%
}%
%%<-------------------------------------------------------------------->
%% Code for definedchecker
%%......................................................................
\@ifdefinable\UD@gobbleto@gef{\long\def\UD@gobbleto@def#1\def{}}%
\@ifdefinable\UD@gobbleto@gdef{\long\def\UD@gobbleto@gdef#1\gdef{}}%
\@ifdefinable\UD@gobbleto@edef{\long\def\UD@gobbleto@edef#1\edef{}}%
\@ifdefinable\UD@gobbleto@xdef{\long\def\UD@gobbleto@xdef#1\xdef{}}%
\newcommand\UD@CheckWhetherNoDef[1]{\expandafter\UD@CheckWhetherNull\expandafter{\UD@gobbleto@def#1\def}}%
\newcommand\UD@CheckWhetherNoGdef[1]{\expandafter\UD@CheckWhetherNull\expandafter{\UD@gobbleto@gdef#1\gdef}}%
\newcommand\UD@CheckWhetherNoEdef[1]{\expandafter\UD@CheckWhetherNull\expandafter{\UD@gobbleto@edef#1\edef}}%
\newcommand\UD@CheckWhetherNoXdef[1]{\expandafter\UD@CheckWhetherNull\expandafter{\UD@gobbleto@xdef#1\xdef}}%
\@ifdefinable\UD@catchto@gef{\long\def\UD@catch@def#1\def#2#3#{\innerdefinedchecker{#1}{\def}{#2}{#3}}}%
\@ifdefinable\UD@catchto@gdef{\long\def\UD@catch@gdef#1\gdef#2#3#{\innerdefinedchecker{#1}{\gdef}{#2}{#3}}}%
\@ifdefinable\UD@catchto@edef{\long\def\UD@catch@edef#1\edef#2#3#{\innerdefinedchecker{#1}{\edef}{#2}{#3}}}%
\@ifdefinable\UD@catchto@xdef{\long\def\UD@catch@xdef#1\xdef#2#3#{\innerdefinedchecker{#1}{\xdef}{#2}{#3}}}%
\newcommand\innerdefinedchecker[5]{\@ifdefinable{#3}{#1#2#3#4{#5}}}%
\@ifdefinable\definedchecker{%
\long\def\definedchecker#1#{%
\UD@CheckWhetherNoDef{#1}{%
\UD@CheckWhetherNoGdef{#1}{%
\UD@CheckWhetherNoEdef{#1}{%
\UD@CheckWhetherNoXdef{#1}{%
#1%
}{\UD@catch@xdef#1}%
}{\UD@catch@edef#1}%
}{\UD@catch@gdef#1}%
}{\UD@catch@def#1}%
}%
}%
\makeatother

\definedchecker\xdef\eclaire{\noexpand\mathbb}
\show\eclaire

\definedchecker\def\R{\ensuremath{\eclaire R}}
\show\R

\definedchecker\outer\global\long\def\myWeirdCommand#1Delimier#2delimiter#{This is my weird command}
\show\myWeirdCommand

% These throw "command already defined"-errors and leave the previous meanings untouched:

\definedchecker\edef\eclaire{Weird Redefinition of eclaire}
\show\eclaire

\definedchecker\gdef\R{Weird Redefinition of R}
\show\R

% Don't do this as \myWeirdCommand is outer.
% \newcommand\myWeirdCommand{Blah}

\begin{document}
\end{document}


Here are the messages that I get into test.log when saving this as test.tex and compiling with pdflatex:

> \eclaire=macro:
->\mathbb .
l.111     \show\eclaire

?
> \R=macro:
->\ensuremath {\eclaire R}.
l.114     \show\R

?
> \myWeirdCommand=\long\outer macro:
#1Delimier#2delimiter{->This is my weird command{.
l.117     \show\myWeirdCommand

?

! LaTeX Error: Command \eclaire already defined.
Or name \end... illegal, see p.192 of the manual.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help.
...

l.121 ...ef\eclaire{Weird Redefinition of eclaire}

?
> \eclaire=macro:
->\mathbb .
l.122     \show\eclaire

?

! LaTeX Error: Command \R already defined.
Or name \end... illegal, see p.192 of the manual.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help.
...

l.124 ...edchecker\gdef\R{Weird Redefinition of R}

?
> \R=macro:
->\ensuremath {\eclaire R}.
l.125     \show\R


From these messages you can see:

In case the command in question within the current scope is already defined to have a meaning other the meaning of the \relax-primitive, \definedchecker delivers an error and does not carry out the assignment.
Otherwise the assignment is carried out.

Be aware that, regarding avoiding overriding definitions of macros that are already defined, this strategy is not completely safe when it comes to defining macros globally.