33

I would like a command \egreg which produces “egreg”. However, there is no reason to limit yourself to one “reg”. Who knows, maybe one day you just feel like writing “egregregregreg" for some reason. So the command should also take an optional argument, specifying the number of “reg”’s you want.

I know there are easy solutions involving loops, but given that it’s April 1, the most ridiculous solution will be accepted.

\documentclass{article}

\NewDocumentCommand\egreg{o}{%
    % something
}

\begin{document}

\egreg % should produce "egreg"
\egreg[0] % should produce "eg"
\egreg[1] % should produce "egreg"
\egreg[2] % should produce "egregreg"
\egreg[5] % should produce "egregregregregreg"

Perhaps we might also want to allow negative values:

\egreg[-1] % should produce "regeg"
\egreg[-2] % should produce "regregeg"

Maybe also complex values?

\egreg[i] % perhaps "$\text{eg} + i\text{reg}$"?

Perhaps someone can also figure out
what to do with quaternionic values?

\end{document}

7
  • 10
    Great April 1st post! I'm sure egreg will answer :D
    – CarLaTeX
    Apr 1 at 7:59
  • 9
    I first thought that this was about a macro that outputs marvellous solutions to (or even just magically solve on-the-fly) tricky TeX problems whenever being used in your code ... Apr 1 at 8:02
  • 4
    @JasperHabicht I promise that if you can come up with a command that can do that consistently, your answer will also be accepted and appropriately awarded. But \newcommand\egreg[1]{Ask ChatGPT about #1} doesn’t count. 😆
    – Gaussler
    Apr 1 at 8:04
  • 4
    I think, on April 1st, the macro should output variations of the string april instead of egreg ... Apr 1 at 10:51
  • 17
    How very egregious. Apr 1 at 18:17

7 Answers 7

26
+500

I think the image-inary part should be drawn with TikZlings:

\documentclass{article}
\usepackage{xstring}
\usepackage{etoolbox}
\usepackage{tikzlings}
\newcommand{\egregnum}[1]{%
  \begin{tikzpicture}[
    every node/.style={inner sep=0pt}, 
    baseline=(a0.base)
    ]
    \node (a0) {eg};
    \ifnumgreater{#1}{0}{%
    \foreach \x [count=\prev from 0] in {1,...,#1}
        \node[anchor=west] (a\x) at (a\prev.east){reg};
        }{%
    \ifnumless{#1}{0}{%
        \foreach \x [evaluate=\x as \numpos using int(\x * -1),
                    evaluate=\x as \prev using int((\x * -1)-1)] 
                    in {-1,...,#1}                  
                \node[anchor=east] (a\numpos) at (a\prev.west){reg};            
            }{}%
        }%
    \end{tikzpicture}
    }

\newcommand{\egregimm}{%
           \raisebox{-.3cm}{\begin{tikzpicture}
                \tikzling[
        scale=0.5,signpost={reg}
        ]
            \end{tikzpicture}
            }}
    
\newcommand{\egreg}[1][1]{%
    \IfDecimal{#1}{%
        \egregnum{#1}%
        }{%
        \StrDel{#1}{ }[\complesso]%
        \StrSubstitute{\complesso}{-}{+}[\contasegni]%
        \StrCount{\contasegni}{+}[\numsegni]%
        \StrPosition[\numsegni]{\contasegni}{+}[\signposition]%
        \StrChar{\complesso}{\signposition}[\segno]%
        \IfStrEq{\segno}{-}{%immaginario negativo
            \StrBehind[\numsegni]{#1}{-}[\partei]%
            \StrSubstitute{\partei}{ }{}[\parteimm]%
            \StrSubstitute{\parteimm}{i}{}[\immaginario]%
            \IfDecimal{\immaginario}{%
                \foreach \cifreimm in {1,...,\immaginario}{\egregimm}
                }{%
                \egregimm
                }%
            \StrBefore[\numsegni]{\complesso}{-}[\reale]%
            \IfDecimal{\reale}{%
                \egregnum{\reale}
                }{%
                \egregnum{0}
                }%
        }{% immaginario positivo
            \StrBefore{\complesso}{+}[\reale]%
            \IfDecimal{\reale}{%
                \egregnum{\reale}
                }{%
                \egregnum{0}
                }%
            \StrBehind{#1}{+}[\partei]%
            \StrSubstitute{\partei}{ }{}[\parteimm]%
            \StrSubstitute{\parteimm}{i}{}[\immaginario]%
            \IfDecimal{\immaginario}{%
                \foreach \cifreimm in {1,...,\immaginario}{\egregimm}
                }{%
                \egregimm
                }%
        }%
    }
}

\begin{document}
    \verb|\egreg|: \egreg % should produce "egreg"
    
    \verb|\egreg[0]|: \egreg[0] % should produce "eg"
    
    \verb|\egreg[1]|: \egreg[1] % should produce "egreg"
    
    \verb|\egreg[2]|: \egreg[2] % should produce "egregreg"
    
    \verb|\egreg[5]|: \egreg[5] % should produce "egregregregregreg"
    
    \verb|\egreg[-1]|: \egreg[-1] % should produce "regeg"
    
    \verb|\egreg[-2]|: \egreg[-2] % should produce "regregeg"
    
    \verb|\egreg[i]|: \egreg[i] % perhaps "$\text{eg} + i\text{reg}$"?

        \verb|\egreg[3+2i]|: \egreg[3+2i] 

        \verb|\egreg[2 + 3i]|: \egreg[2 + 3i]

        \verb|\egreg[-2 + 4i]|: \egreg[-2 + 4i]

        \verb|\egreg[1 - 2i]|: \egreg[1 - 2i]

        \verb|\egreg[-2 - i]|: \egreg[-2 - i]
 
        \verb|\egreg[-i]|: \egreg[-i]

\end{document}

enter image description here

10
  • 7
    Can I hug it? 😍
    – Gaussler
    Apr 2 at 7:12
  • 7
    @Gaussler Of course, you can! And they will be very happy of it!
    – CarLaTeX
    Apr 2 at 7:14
  • 2
    The TikZlings won the competition for you. Congratulations!
    – Gaussler
    Apr 3 at 11:23
  • 2
    @Gaussler I'm very proud if it! Thanks!
    – CarLaTeX
    Apr 3 at 11:28
  • 4
    More confirmation of the TeX.se adage "If you want more rep, add a picture". :)
    – Alan Munn
    Apr 3 at 13:23
18

Out of competition, of course. The most ridiculous answers will be rewarded with bounty points.

Since you don't want expandability, as witnessed by the proposed syntax, here's my version. Note how most endlines are not masked with % and the abundance of unneeded spaces.

\documentclass{article}

\NewDocumentCommand{\egreg}{o}{%
  \IfNoValueTF{#1}{\printegreg{1}}{\printegreg{#1}}%
 }

\NewDocumentCommand{\printegreg}{m}{%
  $
  \begingroup\uccode`~ = `m \uppercase{\endgroup\def~}{\hbox{reg}}
  \mathcode`m = "8000
  \ifnum#1<0 \romannumeral-\number\number#1 000 \fi
  \hbox{eg}
  \ifnum#1>0 \romannumeral\number\number#1 000 \fi
  $%
}

\newcounter{egreg}
\newcount\plainegreg

\begin{document}

\egreg \  should produce ``egreg''

\egreg[0] should produce ``eg''

\egreg[1] should produce ``egreg''

\egreg[2] should produce ``egregreg''

\egreg[5] should produce ``egregregregregreg''

\egreg[-1] should produce ``regeg''

\egreg[-2] should produce ``regregeg''

\setcounter{egreg}{4}

\egreg[\value{egreg}]

\plainegreg=-3

\egreg[\plainegreg]

\end{document}

enter image description here

12
  • 14
    @Mico I'm real, not imaginary.
    – egreg
    Apr 1 at 8:51
  • 6
    Well, we all have our complexities, don’t we?
    – Gaussler
    Apr 1 at 8:52
  • 7
    If I offended you with this competition, I deeply “regreg” it. 😀
    – Gaussler
    Apr 1 at 9:47
  • 8
    @Gaussler Not in the least! I'll award bounties to the most ridiculous answers.
    – egreg
    Apr 1 at 9:48
  • 9
    @Gaussler That's an egregious pun! :-)
    – gusbrs
    Apr 1 at 12:58
16

What we can do in OpTeX:

\optdef\wipet[1]{\if i\the\opt ${\rm wi}+i{\rm pet}$%
   \else
      \tmpnum=\the\opt\relax
      \ifnum\tmpnum<0 \fornum 1..-\tmpnum \do{pet}\fi
      wi%
      \ifnum\tmpnum>0 \fornum 1..\tmpnum \do{pet}\fi
   \fi
}

\wipet\ should produce ``wipet''

\wipet[0]\ should produce ``wi''

\wipet[1]\ should produce ``wipet''

\wipet[2]\ should produce ``wipetpet''

\wipet[5]\ should produce ``wipetpetpetpetpet''

\wipet[-1]\ should produce ``petwi''

\wipet[-2]\ should produce ``petpetwi''

\wipet[i]\ perhaps "${\rm wi} + i{\rm pet}$"

\bye
6
  • 5
    So, wipet is a pet, and wipetpet is like wipet’s pet?
    – Gaussler
    Apr 1 at 12:05
  • 4
    Looking forward to @DavidCarlisle making a solution with a command \carlisle such that \carlisle[2] produces “carlislisle” or something.
    – Gaussler
    Apr 1 at 12:09
  • 3
    @Gaussler true artists can not be mechanically copied in that way. Apr 3 at 20:28
  • 1
    @Gaussler I already contributed this this month, and you expect more? Apr 4 at 9:40
  • 1
    @DavidCarlisle Expect? Of course not. But I’m sure egreg would be happy. 😉 (And good work by the way!)
    – Gaussler
    Apr 4 at 9:44
15
+500

I think the best way to thank egreg for all the help was to solve this exercise using a code roughly as readable as most LaTeX code I can read on this forum (in particular yours egreg, but it's not your fault if LaTeX is not really readable :-P)… but a bit prettified (I took the liberty to modify the minus version to actually be a true inverse, i.e. equal when reading backward).

\documentclass[a4paper]{article}
\usepackage{bxbluf} % See below, from https://gist.github.com/zr-tex8r/7527995

\procbf{\egregBF}{
         +>,-----           --------         
       ------------       ------------       
      --------[<[-]>     ++++++++++++++      
     ++++++++++++++++   +++++++++++++++[     
    >[>++++++++++<-]>   [-<+>]<<---------    
    ------------------ ------------------    
   ---[>+<-],]++++++++ +++++++++++++++++++   
   +++++++++++++++++++++++++++++++++++++++   
   +++++++++++++++++++++++++++++++++++.++.   
  [-]>[->++++++++++++++++++++++++++++++++++  
  +++++++++++++++++++++++++++++++++++++++++  
  +++++++++++++++++++++++++++++++++++++++.-  
    ------------.++.[-]<],[--------------    
     -------------------------------]]<[     
      [-]>,[>[>++++++++++<-]>[-<+>]<<--      
       -------------------------------       
        ---------------[>+<-],]>[->++        
        +++++++++++++++++++++++++++++        
         +++++++++++++++++++++++++++         
          +++++++++++++++++++++++++          
           ++++++++++++++++++++.--           
            .+++++++++++++.[-]<]+            
             +++++++++++++++++++             
              +++++++++++++++++              
               +++++++++++++++               
               +++++++++++++++               
                +++++++++++++                
                 +++++++++++                 
                  +++++++++                  
                   +++.--.                   
                    [-]]♥                    
                     ♥♥♥                     
                      ♥                      
                      ♥         
}


\NewDocumentCommand{\egreg}{O{1}}{\egregBF{#1}}
\begin{document}
\begin{itemize}
\item \texttt{\textbackslash egreg}: \egreg
\item \texttt{\textbackslash egreg[12]}: \egreg[12]
\item \texttt{\textbackslash egreg[-2]}: \egreg[-2]
\end{itemize}

\end{document}

enter image description here

Note that you need to create also a bxbluf.sty file to interpret the Brainfuck in the above code (from https://gist.github.com/zr-tex8r/7527995, slighty improved to remove unwanted space):

% bxbluf.sty

%% package declaration
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{bxbluf}[2013/11/11 v0.2]

%% preparations
\def\bxbf@pkgname{bxbluf}
\def\bxbf@error{\PackageError\bxbf@pkgname}
\def\bxbf@warn{\PackageWarningNoLine\bxbf@pkgname}
\def\bxbf@err@umbgr{%
  \bxbf@error{Unmatched [ found}\@ehc
}
\def\bxbf@err@umegr{%
  \bxbf@error{Unmatched ] found}\@ehc
}
\def\bxbf@warn@hichr{%
  \bxbf@warn{Non 8-bit character found}%
}
\def\bxbf@warn@ineof{%
  \bxbf@warn{End-of-input reached}%
}
%
\newif\ifbxbf@inloop
\newif\ifbxbf@g@error
\newif\ifbxbf@optok
\providecommand*\bxDebug[1]{}

%--------------------------------------- base

%% variables
\newcount\bxbf@count
\let\bxbf@prcode\@empty

%% \bxbf@op@list : operator list
\def\bxbf@op@list{%
  \do\bxbf@AP\do\bxbf@AV\do\bxbf@ID\do\bxbf@OD\do\bxbf@LP
  \do\bxbf@RP\do\bxbf@RV\do\bxbf@AX\do\bxbf@RX\do\bxbf@SF
}

%% \bxbf@op@frozen
\let\bxbf@op@frozen\relax

%% \bxbf@op@noop
\def\bxbf@op@noop#1{}

%% \bxbf@switch@all@op\CS
\def\bxbf@switch@all@op#1{%
  \let\bxbf@tmpa#1%
  \let\do\bxbf@switch@all@op@do \bxbf@op@list
}
\def\bxbf@switch@all@op@do#1{%
  \let#1\bxbf@tmpa
}

%% \bxbf@modulo{<num>}
\def\bxbf@modulo#1{%
  \@tempcnta=#1\relax \bxbf@count\@tempcnta
  \divide\@tempcnta\bxbf@rbase \multiply\@tempcnta\bxbf@rbase
  \advance\bxbf@count-\@tempcnta
}

%% \bxbf@show
% for debug
\def\bxbf@show{%
  \bxbf@switch@all@op\bxbf@op@frozen
  \bxDebug{prog:\bxbf@prcode}%
}

%--------------------------------------- \scantokens emulation
\ifx\scantokens\@undefined
  % when \scantokens is unavailable
  \newwrite\bxbf@tempfile
  \def\bxbf@tempfilename{\bxbf@pkgname.out}

  \def\bxbf@scantokens#1{%
    \begingroup
      \toks@={#1}%
      \immediate\openout\bxbf@tempfile=\bxbf@tempfilename\relax
      \immediate\write\bxbf@tempfile{\the\toks@}%
      \immediate\closeout\bxbf@tempfile
    \endgroup
    \input{\bxbf@tempfilename}%
  }%

\else
  % uses \scantokens if available
  \let\bxbf@scantokens\scantokens
\fi
%--------------------------------------- LaTeX interface

%% variables
\newcount\bxbf@proc@maxid
\let\bxbf@decl@mode\relax
\let\bxbf@out@verbatim\relax
\let\bxbf@eofval=*

%%<*> \execbf[*] / \execbfwithinput[*] / \procbf[*]
\DeclareRobustCommand*\execbf{%
  \@ifstar{\bxbf@procbf{n}{1}}{\bxbf@procbf{n}{0}}%
}
\DeclareRobustCommand*\execbfwithinput{%
  \@ifstar{\bxbf@procbf{i}{1}}{\bxbf@procbf{i}{0}}%
}
\DeclareRobustCommand*\procbf{%
  \@ifstar{\bxbf@procbf{p}{1}}{\bxbf@procbf{p}{0}}%
}
\def\bxbf@procbf#1#2{%
  \let\bxbf@decl@mode=#1\relax
  \chardef\bxbf@out@verbatim=#2\relax
  \def\bxbf@proc@id{0}%
  \if i\bxbf@decl@mode
    \let\bxbf@tmpa\bxbf@procbf@winput
  \else\if p\bxbf@decl@mode
    \advance\bxbf@proc@maxid\@ne
    \edef\bxbf@proc@id{\the\bxbf@proc@maxid}%
    \let\bxbf@tmpa\bxbf@procbf@wproc
  \else
    \let\bxbf@input\@empty
    \let\bxbf@tmpa\bxbf@procbf@a
  \fi\fi
  \bxbf@tmpa
}
\def\bxbf@procbf@winput#1{% <input>
  \def\bxbf@input{#1}%
  \bxbf@procbf@a
}
\def\bxbf@procbf@wproc#1{% \ProcCS
  \def\bxbf@proc@cs{\noexpand#1}%
  \bxbf@procbf@a
}
\def\bxbf@procbf@a#1{% <program>
  \begingroup
    \global\expandafter\chardef\csname bxbf@OutVerb/\bxbf@proc@id\endcsname
     =\bxbf@out@verbatim
    \bxbf@parse{#1}%
    \bxbf@optimize
    \global\expandafter\let\csname bxbf@PrArray/\bxbf@proc@id\endcsname
     =\bxbf@prcode
  \endgroup
  \ifnum\bxbf@proc@id>0
    \edef\bxbf@tmpa{%
      \gdef\bxbf@proc@cs{\noexpand\bxbf@invoke@proc{\bxbf@proc@id}}%
    }%
    \bxbf@tmpa
  \else % immediate execution
    \bxbf@invoke@proc{\bxbf@proc@id}{\bxbf@input}%
  \fi
}

%% \bxbf@invoke@proc{<id>}{<input>}
\def\bxbf@invoke@proc#1#2{%
  \begingroup
    \bxbf@stringify\bxbf@input{#2}%
    \expandafter\let\expandafter\bxbf@prcode
     \csname bxbf@PrArray/#1\endcsname
    \bxbf@execute
    \xdef\bxbf@g@tmpa{\noexpand\bxbf@process@str
      {\csname bxbf@OutVerb/#1\endcsname}{\bxbf@output}}%
  \endgroup
  \bxbf@g@tmpa
}
\def\bxbf@process@str#1#2{%
  \ifnum#1>\z@
    \begingroup
      \let\bxbfLF\newline \let\bxbfSP\ %
      #2\relax
    \endgroup
  \else
    \begingroup
      \def\bxbfLF{^^J}\def\bxbfSP{ }%
      \xdef\bxbf@g@tmpa{\noexpand\bxbf@scantokens{#2}}%
    \endgroup
    \bxbf@g@tmpa
  \fi
}

%% \bxbf@stringify\CS{<text>}
\def\bxbf@stringify#1#2{%
  \edef\bxbf@tmpa{#2}%
  \expandafter\bxbf@stringify@a\meaning\bxbf@tmpa\bxbf@end#1%
}
\def\bxbf@stringify@a#1->#2\bxbf@end#3{%
  \def#3{#2}%
}

%%<*> \bfeofvalue{<val>}
\newcommand*\bfeofvalue[1]{%
  \def\bxbf@tmpa{#1}%
  \ifx\bxbf@tmpa\bxbf@@star \let\bxbf@eofval=*\relax
  \else\ifx\bxbf@tmpa\bxbf@@bang \let\bxbf@eofval=!\relax
  \else \afterassignment\bxbf@eofvalue@a\bxbf@count=\bxbf@tmpa\bxbf@tn
  \fi\fi
}
\def\bxbf@eofvalue@a#1\bxbf@tn{%
  \def\bxbf@tmpa{#1}%
  \ifx\bxbf@tmpa\@empty
    \bxbf@modulo\bxbf@count
    \ifnum\bxbf@count<\z@ \advance\bxbf@count\bxbf@rbase \fi
    \chardef\bxbf@eofval\bxbf@count
  \else \bxbf@count=\bxbf@tn
  \fi
}
\let\bxbf@tn\relax
\def\bxbf@@star{*}
\def\bxbf@@bang{!}

%--------------------------------------- parse

%% variables
\let\bxbf@block\@empty
\let\bxbf@prev@op\@empty
\let\bxbf@source@rest\@empty
\mathchardef\bxbf@rbase=256
\mathchardef\bxbf@mcmax="7FFF

%% \bxbf@chk
\def\bxbf@chk{\space}

%% \bxbf@parse
\long\def\bxbf@parse#1{%
  \bxbf@switch@all@op\bxbf@op@frozen
  \bxbf@inloopfalse
  \global\bxbf@g@errorfalse
  \edef\bxbf@tmpa{%
    \noexpand\bxbf@parse@block{#1\noexpand\bxbf@chk}}%
  \bxbf@tmpa
  \ifbxbf@g@error \let\bxbf@prcode\@empty
  \else \let\bxbf@prcode\bxbf@block
  \fi
}

%% \bxbf@parse@block
\long\def\bxbf@parse@block#1{%
  \let\bxbf@prev@op\@empty \bxbf@count\z@
  \let\bxbf@block\@empty
  \bxbf@parse@loop@a#1\bxbf@end
}

%% \bxbf@parse@loop
\def\bxbf@parse@loop{%
  \futurelet\bxbf@tmpa\bxbf@parse@loop@a
}
\def\bxbf@parse@loop@a{%
  \ifx\bxbf@tmpa\bgroup \expandafter\bxbf@parse@loop@b
  \else \expandafter\bxbf@parse@loop@ab
  \fi
}
\def\bxbf@parse@loop@ab{%
  \ifx\bxbf@tmpa\@sptoken \expandafter\bxbf@parse@loop@ac
  \else \expandafter\bxbf@parse@loop@c
  \fi
}
\expandafter\def\expandafter\bxbf@parse@loop@ac\space{%
  \bxbf@parse@loop
}
\long\def\bxbf@parse@loop@b#1{%
  \bxbf@parse@loop#1%
}
\long\def\bxbf@parse@loop@c#1{%
  \csname bxbf@p@h/\string#1\endcsname
  \bxbf@parse@loop
}
%% \bxbf@aprse@flush
\def\bxbf@parse@flush{%
  \ifnum\bxbf@count=\z@\else
    \edef\bxbf@block{\bxbf@block\bxbf@prev@op{\the\bxbf@count}}%
  \fi
}
%% \bxbf@aprse@nonaccum
\def\bxbf@parse@nonaccum#1{%
  \bxbf@parse@flush
  \def\bxbf@prev@op{#1}\bxbf@count\@ne
}
%% \bxbf@aprse@accum
\def\bxbf@parse@accum#1#2{%
  \def\bxbf@tmpa{#1}%
  \ifx\bxbf@prev@op\bxbf@tmpa
    \advance\bxbf@count#2%
  \else
    \bxbf@parse@flush
    \bxbf@count#2\def\bxbf@prev@op{#1}
  \fi
}
%% \bxbf@aprse@new@block
\long\def\bxbf@parse@new@block#1#2\bxbf@end{% #1 gobbled
  \bxbf@parse@flush
%\bxDebug{new:\bxbf@block}%
  \begingroup
    \bxbf@inlooptrue
    \bxbf@parse@block{#2}%
    \global\let\bxbf@g@tmpa\bxbf@block
    \global\let\bxbf@g@tmpb\bxbf@source@rest
  \endgroup
  \let\bxbf@source@rest\bxbf@g@tmpb
  \edef\bxbf@block{\bxbf@block\bxbf@LP{\bxbf@g@tmpa}}%
%\bxDebug{back:\bxbf@block}%
  \let\bxbf@prev@op\@empty \bxbf@count\z@
  \expandafter\bxbf@parse@loop\bxbf@source@rest\bxbf@end
}
%% \bxbf@aprse@end@block
\long\def\bxbf@parse@end@block#1#2\bxbf@end{% #1 gobbled
  \bxbf@parse@flush
  \ifbxbf@inloop
    \def\bxbf@source@rest{#2}%
  \else
    \bxbf@err@umegr
    \global\bxbf@g@errortrue
    \let\bxbf@source@rest\@empty
  \fi
}
%% \bxbf@aprse@finale
\long\def\bxbf@parse@finale#1#2\bxbf@end{% #1 gobbled
  \bxbf@parse@flush
  \ifbxbf@inloop
    \bxbf@err@umbgr
    \global\bxbf@g@errortrue
    \def\bxbf@source@rest{\bxbf@chk}%
  \fi
}

%% \bxbf@decl@handler{<token>}{<body>}
\def\bxbf@decl@handler#1{%
  \expandafter\def\csname bxbf@p@h/#1\endcsname
}
\bxbf@decl@handler{+}{\bxbf@parse@accum\bxbf@AV\@ne}
\bxbf@decl@handler{-}{\bxbf@parse@accum\bxbf@AV\m@ne}
\bxbf@decl@handler{>}{\bxbf@parse@accum\bxbf@AP\@ne}
\bxbf@decl@handler{<}{\bxbf@parse@accum\bxbf@AP\m@ne}
\bxbf@decl@handler{,}{\bxbf@parse@nonaccum\bxbf@ID}
\bxbf@decl@handler{.}{\bxbf@parse@nonaccum\bxbf@OD}
\bxbf@decl@handler{[}{\bxbf@parse@new@block}
\bxbf@decl@handler{]}{\bxbf@parse@end@block}
\bxbf@decl@handler{\string\bxbf@chk}{\bxbf@parse@finale}

%--------------------------------------- optimize

%% variables
\let\bxbf@g@block\@empty

%% \bxbf@g@addto@block
\def\bxbf@g@addto@block{\g@addto@macro\bxbf@g@block}

%% \bxbf@opt@addop
\def\bxbf@opt@addop#1#2{%
  \bxbf@g@addto@block{#1#2}%
}

%% \bxbf@intern{<num>}\cont
\edef\bxbf@H{\expandafter\@gobble\string\#}
\def\bxbf@intern#1{%
  \expandafter\bxbf@intern@a\csname\bxbf@H\number#1%
   \expandafter\endcsname\number#1\relax
}
\def\bxbf@intern@a#1#2\relax#3{%
  \ifx#1\relax
    \ifnum#2>\bxbf@mcmax \gdef#1{#2 }%
    \else \global\mathchardef#1=#2\relax
    \fi
  \fi
  #3#1%
}

%% \bxbf@intern@red{<num>}\cont
\def\bxbf@intern@red#1{%
  \bxbf@modulo{#1}%
  \bxbf@intern\bxbf@count
}

%% \bxbf@optimize
\def\bxbf@optimize{%
  \bxbf@switch@opt
  \global\let\bxbf@g@block\@empty
  \bxbf@prcode
  \let\bxbf@prcode\bxbf@g@block
}

%% \bxbf@switch@opt
\def\bxbf@switch@opt{%
  \let\bxbf@AP\bxbf@opt@AP\let\bxbf@AV\bxbf@opt@AV
  \let\bxbf@ID\bxbf@opt@ID\let\bxbf@OD\bxbf@opt@OD
  \let\bxbf@LP\bxbf@opt@LP
  \let\bxbf@RP\bxbf@op@error\let\bxbf@RV\bxbf@op@error
  \let\bxbf@AX\bxbf@opt@AX\let\bxbf@RX\bxbf@op@error
  \let\bxbf@SF\bxbf@op@error
}

%% \bxbf@opt@ID / \bxbf@opt@OD
\def\bxbf@tmpa#1{%
  \def\bxbf@opt@ID##1{\bxbf@g@addto@block{\bxbf@ID#1}}%
  \def\bxbf@opt@OD##1{\bxbf@g@addto@block{\bxbf@OD#1}}%
}
\bxbf@intern{1}\bxbf@tmpa

%% \bxbf@opt@AP
\def\bxbf@opt@AP#1{%
  \ifnum#1<\z@ \bxbf@intern{-#1}{\bxbf@opt@addop\bxbf@RP}%
  \else        \bxbf@intern{+#1}{\bxbf@opt@addop\bxbf@AP}%
  \fi
}
%% \bxbf@opt@AV
\def\bxbf@opt@AV#1{%
  \ifnum#1<\z@ \bxbf@intern@red{-#1}{\bxbf@opt@addop\bxbf@RV}%
  \else        \bxbf@intern@red{+#1}{\bxbf@opt@addop\bxbf@AV}%
  \fi
}
%% \bxbf@opt@AX
\def\bxbf@opt@AX#1{%
  \ifnum#1<\z@ \bxbf@intern@red{-#1}{\bxbf@opt@addop\bxbf@RX}%
  \else        \bxbf@intern@red{+#1}{\bxbf@opt@addop\bxbf@AX}%
  \fi
}

%% \bxbf@opt@check
\def\bxbf@opt@check#1{%
  \bxbf@optokfalse
  \begingroup
    \bxbf@switch@all@op\bxbf@opt@check@ng
    \let\bxbf@AV\bxbf@opt@check@AV
    \let\bxbf@AP\bxbf@opt@check@AP
    \bxbf@count\z@ \@tempcntb\z@
    #1\bxbf@opt@check@fin
  \endgroup
}
\def\bxbf@opt@check@ng#1\bxbf@opt@check@fin{}
\def\bxbf@opt@check@AP#1{%
  \advance\bxbf@count#1\relax
}
\def\bxbf@opt@check@AV#1{%
  \ifnum\bxbf@count=\z@
    \advance\@tempcntb#1\relax
  \fi
}

%% \bxbf@opt@check@fin
\def\bxbf@opt@check@fin{%
  \ifnum\bxbf@count=\z@ \ifnum\@tempcntb=\m@ne
    \aftergroup\bxbf@optoktrue
  \fi\fi
}

%% \bxbf@opt@LP
\def\bxbf@opt@LP#1{%
  \begingroup
    \bxbf@opt@check{#1}%
    \let\bxbf@save@block\bxbf@g@block
    \global\let\bxbf@g@block\@empty
    \ifbxbf@optok
      \let\bxbf@AV\bxbf@AX
    \fi
    #1%
    \expandafter\bxbf@opt@LP@a\expandafter{\bxbf@g@block}%
  \endgroup
}
\def\bxbf@opt@LP@a#1{%
  \let\bxbf@g@block\bxbf@save@block
  \ifbxbf@optok \g@addto@macro\bxbf@g@block{\bxbf@SF{#1}}%
  \else \g@addto@macro\bxbf@g@block{\bxbf@LP{#1}}%
  \fi
}

%% \bxbf@opt@add\CS{<arg>}
\def\bxbf@opt@add#1#2{%
  \g@addto@macro\bxbf@g@block{#1{#2}}%
}

%--------------------------------------- execute
\edef\bxbf@restorecc{\catcode127=\the\catcode127\relax}
\catcode127=12

%% variables
\newcount\bxbf@dptr
\let\bxbf@str@in\@empty
\let\bxbf@str@out\@empty
\chardef\bxbf@zero=0
\chardef\bxbf@lctr=0

%% \bxbf@execute
\def\bxbf@execute{%
%\bxbf@show
  \bxbf@switch@exec
  \global\let\bxbf@str@in\bxbf@input
  \global\let\bxbf@str@out\@empty
  \global\bxbf@g@errorfalse
  \bxbf@dptr\z@
  \bxbf@prcode\bxbf@exec@fin
  \ifbxbf@g@error \let\bxbf@output\@empty
  \else \let\bxbf@output\bxbf@str@out
  \fi
}
\let\bxbf@exec@fin\relax

%% \bxbf@exec@halt
% NB. This is not counted as error.
\def\bxbf@exec@halt#1\bxbf@exec@fin{}

%% \bxbf@swtich@exec
\def\bxbf@switch@exec{%
  \let\bxbf@AP\bxbf@exec@AP\let\bxbf@AV\bxbf@exec@AV
  \let\bxbf@ID\bxbf@exec@ID\let\bxbf@OD\bxbf@exec@OD
  \let\bxbf@LP\bxbf@exec@LP
  \let\bxbf@RP\bxbf@exec@RP\let\bxbf@RV\bxbf@exec@RV
  \let\bxbf@AX\bxbf@exec@AX\let\bxbf@RX\bxbf@exec@RX
  \let\bxbf@SF\bxbf@exec@SF
}

%% bxbf@exec@AP
\def\bxbf@exec@AP#1{%
  \advance\bxbf@dptr#1%
%\bxDebug{AP:\number#1;\number\bxbf@dptr}%
}
%% bxbf@exec@RP
\def\bxbf@exec@RP#1{%
  \advance\bxbf@dptr-#1%
%\bxDebug{RP:\number#1;\number\bxbf@dptr}%
}

%% bxbf@exec@AV
\def\bxbf@exec@AV{%
  \expandafter\bxbf@exec@AV@a\csname ^^?\the\bxbf@dptr\endcsname}
\def\bxbf@exec@AV@a#1#2{%
  \ifx#1\relax \chardef#1#2%
  \else
    \bxbf@count#1\advance\bxbf@count#2%
    \ifnum\bxbf@count<\bxbf@rbase\else \advance\bxbf@count-\bxbf@rbase \fi
    \chardef#1\bxbf@count
  \fi
%\bxDebug{AV:#1:\the#2;\the#1}%
}
%% bxbf@exec@RV
\def\bxbf@exec@RV{%
  \expandafter\bxbf@exec@RV@a\csname ^^?\the\bxbf@dptr\endcsname}
\def\bxbf@exec@RV@a#1#2{%
  \ifx#1\relax \chardef#1\bxbf@zero \fi
  \bxbf@count#1\advance\bxbf@count-#2%
  \ifnum\bxbf@count<\z@ \advance\bxbf@count\bxbf@rbase \fi
  \chardef#1\bxbf@count
%\bxDebug{RV:#1:\the#2;\the#1}%
}

%% bxbf@exec@ID
\def\bxbf@exec@ID{%
  \expandafter\bxbf@exec@ID@a\csname ^^?\the\bxbf@dptr\endcsname}
\def\bxbf@exec@ID@a#1#2{%
  \ifx#1\relax \chardef#1\bxbf@zero \fi
  \bxbf@count#1%
  \bxbf@get@char
  \ifnum\bxbf@count<\z@ \expandafter\bxbf@exec@halt \fi
  \chardef#1\bxbf@count
%\bxDebug{ID:#1;\the#1}%
}

%% bxbf@exec@OD
\def\bxbf@exec@OD{%
  \expandafter\bxbf@exec@OD@a\csname ^^?\the\bxbf@dptr\endcsname}
\def\bxbf@exec@OD@a#1#2{%
  \ifx#1\relax \chardef#1\bxbf@zero\fi%
  \bxbf@count#1%
  \bxbf@put@char%
%\bxDebug{OD:#1;\the#1}%
}

%% bxbf@exec@OD
\def\bxbf@exec@LP{%
  \expandafter\bxbf@exec@LP@a\csname ^^?\the\bxbf@dptr\endcsname}
\def\bxbf@exec@LP@a#1{%
  \ifx#1\relax \chardef#1\bxbf@zero\fi%
%\bxDebug{LP:#1;\the#1}%
  \ifnum#1=\z@ \expandafter\@gobble%
  \else\expandafter\bxbf@exec@LP@b%
  \fi%
}
\def\bxbf@exec@LP@b#1{%
  #1\bxbf@exec@LP{#1}%
}

%% bxbf@exec@SF
\def\bxbf@exec@SF{%
  \expandafter\bxbf@exec@SF@a\csname ^^?\the\bxbf@dptr\endcsname}
\def\bxbf@exec@SF@a#1#2{%
  \ifx#1\relax \chardef#1\bxbf@zero\fi%
  \chardef\bxbf@lctr#1%
  #2%
}

%% bxbf@exec@AX
\def\bxbf@exec@AX{%
  \expandafter\bxbf@exec@AX@a\csname ^^?\the\bxbf@dptr\endcsname}
\def\bxbf@exec@AX@a#1#2{%
  \ifx#1\relax \chardef#1\bxbf@zero\fi
  \bxbf@count#2\multiply\bxbf@count\bxbf@lctr\advance\bxbf@count#1%
  \ifnum\bxbf@count<\bxbf@rbase\else\bxbf@modulo\bxbf@count\fi%
  \chardef#1\bxbf@count%
%\bxDebug{AX:#1:\the#2;\the#1}%
}
%% bxbf@exec@RX
\def\bxbf@exec@RX{%
  \expandafter\bxbf@exec@RX@a\csname ^^?\the\bxbf@dptr\endcsname}
\def\bxbf@exec@RX@a#1#2{%
  \ifx#1\relax%
    \chardef#1\bxbf@zero\fi%
  \bxbf@count#2\multiply\bxbf@count-\bxbf@lctr\advance\bxbf@count#1%
  \ifnum\bxbf@count<\z@ \bxbf@modulo\bxbf@count\fi%
  \ifnum\bxbf@count<\z@ \advance\bxbf@count\bxbf@rbase\fi%
  \chardef#1\bxbf@count%
%\bxDebug{RX:#1:\the#2;\the#1}%
}

\bxbf@restorecc
%--------------------------------------- virtual I/O

%% variables
\chardef\bxbfLF=10
\chardef\bxbfSP=32

%% \bxbf@get@char
\def\bxbf@get@char{%
  \ifx\bxbf@str@in\@empty \bxbf@get@char@mt%
  \else%
    \expandafter\bxbf@get@char@a\bxbf@str@in\bxbf@end%
  \fi%
}
\def\bxbf@get@char@a{%
  % don't discard spaces!
  \futurelet\bxbf@tmpa\bxbf@get@char@b%
}
\def\bxbf@get@char@b{%
  \ifx\bxbf@tmpa\@sptoken%
    \expandafter\bxbf@get@char@d%
  \else%
    \expandafter\bxbf@get@char@c%
  \fi%
}
\def\bxbf@get@char@c#1#2\bxbf@end{%
  \bxbf@count`#1\relax \gdef\bxbf@str@in{#2}%
  \ifnum\bxbf@count>\@cclv%
    \expandafter\bxbf@invalid@char%
  \fi
}
\def\bxbf@get@char@d{%
  \afterassignment\bxbf@get@char@e \let\bxbf@tmpa=%
}
\def\bxbf@get@char@e#1\bxbf@end{%
  \bxbf@count\bxbfSP \gdef\bxbf@str@in{#1}%
}
\def\bxbf@invalid@char{%
  \bxbf@warn@hichr%
  \bxbf@count\z@% non 8-bit char is replaced by zero
}
\def\bxbf@get@char@mt{%
  \ifx!\bxbf@eofval%
    \bxbf@warn@ineof%
    \bxbf@count\m@ne%
  \else\ifx*\bxbf@eofval\else%
    \bxbf@count\bxbf@eofval%
  \fi\fi%
}

%% \bxbf@put@char
\def\bxbf@put@char{%
  \lccode`!=\bxbf@count%
  \lowercase{%
    \xdef\bxbf@str@out{\bxbf@str@out%
      \ifnum\bxbf@count=\bxbfLF \bxbfLF%
      \else\ifnum\bxbf@count=\bxbfSP \bxbfSP%
      \else !\fi\fi}%
  }%
%\bxDebug{OUT:\bxbf@str@out:\the\bxbf@count}%
}

%--------------------------------------- all done
\endinput
%% EOF
4
  • 1
    Excellent ridiculous solution! You are right about the minus sign, that is the logical behaviour, but I only realized that after the answers had started coming in, so we're stuck with the original question.
    – Gaussler
    Apr 4 at 6:03
  • 7
    This is worth another bounty!
    – egreg
    Apr 4 at 12:53
  • @egreg Ahah thanks, I'm happy to see that you like it, I would never have expected to ever receive a bounty from you ^^ (the fact that you have never asked a single question does not help! tex.stackexchange.com/users/4427/egreg?tab=questions)
    – tobiasBora
    Apr 4 at 13:52
  • 1
    Yes, @egreg is usually the one who receives bounties. Still, I hope that some day, just for fun, he will ask some question in here.
    – Gaussler
    Apr 4 at 16:01
14

I like recursions:

\documentclass{article}

\NewDocumentCommand\egreg{O{1}}{%
  \ifnum #1>0 eg\reg{#1}\else\ifnum #1<0 \reg{-#1}\fi eg\fi
}
\newcommand*{\reg}[1]{%
  \ifnum #1>0 \-reg\reg{\numexpr #1-1\relax}\fi
}

\begin{document}

\raggedright

\egreg{}  should produce ``egreg"

\egreg[0] should produce ``eg"

\egreg[1] should produce ``egreg"

\egreg[2] should produce ``egregreg"

\egreg[5] should produce ``egregregregregreg"

\medskip
Perhaps we might also want to allow negative values:

\egreg[-1] should produce ``regeg"

\egreg[-2] should produce ``regregeg"

\medskip
And also with hyphenation: \egreg[100]

\end{document}

Yes, handling of complex values is missing.

3
  • 1
    Good, in case I want to write “egregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregregreg”.
    – Gaussler
    Apr 1 at 12:03
  • In general, isn’t it safer to use '' (two apostrophes) instead of " (quotation mark), especially since babel has a tendency to make the latter active?
    – Gaussler
    Apr 2 at 12:54
  • 1
    @Gaussler Generally it would be safer and better to use csquotes. But IMHO the question was not about safer and better solutions. ;-) (But honestly, I was simply too lazy to replace all the quotes.)
    – cabohah
    Apr 3 at 6:48
13
+500

Just for comparison, here is a version in Metapost (with apologies for being so far from the brief, apart from the "ridiculous" bit).

enter image description here

Compile with lualatex. (Here be dragons...)

\documentclass[border=5mm]{standalone}
\usepackage{luamplib}
\begin{document}
\begin{mplibcode}
picture payload; 
payload = textext("$\vcenter{\hbox{egreg}}\;$");
payload := payload scaled (1/abs(lrcorner payload - llcorner payload));
vardef dragon(expr level, a, b, r) = 
    if level = 0:
        draw a--b withcolor 3/4;
        draw payload zscaled (b-a) shifted a;
    else:
        save p; pair p;
        p = 0.7071067811865476[a, b] rotatedabout(a, r); 
        
        dragon(level-1, a, p, +abs(r));
        dragon(level-1, p, b, -abs(r)); 
    fi
enddef;
beginfig(1);
        dragon(11, origin, 600 right, 45); 
endfig;
\end{mplibcode}
\end{document}
1
  • @egreg I hope a "thank you" comment is allowed. Or perhaps I should say "Grazie mille!"
    – Thruston
    Apr 6 at 16:31
10

The following, LuaLaTeX-based solution probably won't qualify as being completely ridiculous, since it doesn't actually employ any loop-type control structures; it is left as an exercise to the motivated reader to replace Lua's string.rep function with a suitable for, while, or repeat .. until loop. Also, to keep @egreg's blood pressure from spiking up, I use \mathrm instead of \text directives...

enter image description here

% !TEX TS-program = lualatex
\documentclass{article}
\usepackage{luacode}

\begin{luacode*}
function egreg ( n )
  if n=="" then
    tex.sprint ("egreg")
  elseif n=="i" then
    tex.sprint ( "\\ensuremath{\\mathrm{eg}+i\\mathrm{reg}}" )
  else
    n = tonumber ( n )
    if n<0 then
      tex.sprint (        string.rep ( "reg",-n) .. "eg" )
    else
      tex.sprint ( "e" .. string.rep ( "gre", n) .. "g" )
    end
  end
end
\end{luacode*}
%% LaTeX-side code:
\newcommand\egreg[1][]{\directlua{egreg("#1")}}

\begin{document}

\obeylines % just for this example
\egreg 
\egreg[0] 
\egreg[1] 
\egreg[5] 
\egreg[-1] 
\egreg[-2]
\egreg[i] 

\end{document}
4
  • 2
    What about mixed expressions like 3+2i? 😉
    – Gaussler
    Apr 1 at 8:52
  • 1
    @Gaussler - Should \egreg[3+2i] evaluate to \egreg[3]+i\egreg[2]? Or maybe its complex conjugate? :-)
    – Mico
    Apr 1 at 9:06
  • 2
    Probably. But your guess is as good as mine. 😆
    – Gaussler
    Apr 1 at 9:29
  • 4
    @Gaussler - Upon reflection, I've decided to leave the job of creating a complex-valued \egreg macro as an extra-credit assignment to readers...
    – Mico
    Apr 1 at 13:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .