6

Is it possible to create a macro, such that everything that is between the string composed of the characters "whitespace", "{", "L" and the string composed of "L", "}", "whitespace" is not displayed, when I compile my file? I.e. the line " {L HelloL} World" should compile to "World".

I deliberately did not specify any restriction on how this macro could be programmed. The ideal way for me would be that there is a variable in my LaTeX file, lets call it \switch, such than when \switch=1, everything between the strings described above is not displayed and when \switch=0 it just compiles as usual - but I'd also be happy with less perfect ways to do this, like having a macro for my *.tex text file, that manually deletes everything between those string.

The goal I'm after is that there are several portions of the text that are between those strings and I usually like to have those portions in my text. But there are also occasions when I temporarily don't want to have them there. Having an automated way to display them or not would save me a lot of time: I wouldn't always have to manually search through them.

Please take note that my programming skills, besides LaTeX, are rather limited.

  • 3
    Well, if you could live with writing something like \hidemesometimes{Hello} instead, you can just define \newcommand{\hidemesometimes}[1]{#1} if you want to see the text or \newcommand{\hidemesometimes}[1]{\relax} (or \newcommand{\hidemesometimes}[1]{\leavevmode\unskip}) if you don't. (There might be some rough edges here.) LuaTeX can do very fancy things as well, see Macro: Replace all occurrences of a word for something that comes close. – moewe Aug 22 '15 at 14:13
  • @moewe This would indeed be a possibility, although I'd only use it, if nothing more elegant comes up. I didn't knew what LuaTeX really was, until you mentioned it. After I read the Wikipedia article on it, it seems that the kind of functionality I want could not even be done in plain LaTeX (except editing directly the *.tex file via some fancy text editor), as Lua's advantage over LaTeX seems to be to allow (among other things) scripting, right ? – l7ll7 Aug 24 '15 at 5:52
  • 1
    I wouldn't want to say it is impossible with "normal" (La)TeX - you can do some crazy stuff there (but I would certainly not be the one to implement such a thing). One of the upsides of LuaTeX is "native" Lua (scipt) execution which would allow for such a thing; there are some other advantages such as full Unicode support as well. The LaTeX-way would be to create such a macro as described above. You can do search-and-replace in your editor to get the new form. I have also read about letting the C preprocessor pre-process TeX documents (can't find the link right now). – moewe Aug 24 '15 at 8:21
  • 1
    I'm really sorry, I still can't find that link. If you want to start a bounty it might be a good idea to add a small example document that shows the use case and allows people to play around with. (Why exactly is the string always {L ... L} if I might ask? Is there any way to change that?) – moewe Aug 28 '15 at 13:27
  • 1
    @moewe Thanks for the link, although after working with it I couldn't get it to remove things within {L and L}, only repeating words. It thus seems I have to stick to your first solution, as Lua scripting is too time consuming for me to learn right now - but I'm going to open a bounty, maybe slicker solutions will come along, or someone in an ideal case will perhaps provide a ready-made script. – l7ll7 Aug 30 '15 at 13:58
4
+50

Control sequence approach

As far as you asked about a macro here is a solution using delimited arguments (similar to @jfbu's solution) with a canonical macro introduced through the escape character \, that incorporates your syntax design:

\documentclass{article}

\newcount\switch
\switch=0

\def\maybehide#1{\maybehidei#1}
\def\maybehidei L #1 L{\ifnum\switch>0\unskip\else#1\fi}

\begin{document}
\maybehide{L Hello L} World
\end{document}

Active character approach

Now, your actual question turns out to be about strings that use no escape character in terms of (La)TeX. So here is what you can do: Firstly, you need to change the category codes of { and } to active. Then you can use them to define (again) a macro with delimited argument where you need to assign new characters to catcodes 1 and 2 as the old ones are lost now. A Plain TeX example could look like

\newcount\switch
\switch=0

\catcode`\(=1
\catcode`\)=2
\catcode`\{\active
\catcode`\}\active
\def{L #1 L}(\ifnum\switch>0\unskip\else#1\fi)

{L Hello L} World

\bye

But, doing so you will break a lot of things. To circumvent most of those problems you would have to say something like

\def\mymacro#1{\bgroup\bf World: #1\egroup}% test macro

\newcount\switch
\switch=1

\catcode`\(=1
\catcode`\)=2
\catcode`\{\active
\catcode`\}\active
\def\:(\let\sptoken= ) \:  
\def{(\bgroup\futurelet\next\braceaux)
\def\braceaux(\ifx L\next\expandafter\maybehide\fi)
\def\maybehide L(\afterassignment\maybehideaux\let\spacechecker= )
\def\maybehideaux(%
  \if\noexpand\spacechecker\sptoken
    \expandafter\maybehideprocess\else L\spacechecker\fi)
\def\maybehideprocess #1L}(\ifnum\switch>0\unskip\else#1\fi\unskip)
\def}(\egroup)
\catcode`\(=12
\catcode`\)=12

{L Hello L} World

{L
  \mymacro{Hello}
L}

{\it Testing a simple group}

Empty group after \TeX{}

{LLLLLLLL}

\bye

As one of your comments to the OP states that you are not bound to braces yet, and as the last hack is rather dirty, here is a version that uses ~. (Still dirty, but a little cleaner though.) It does nearly the same thing as the last example.

\documentclass{article}

\newcount\switch
\switch=0

\catcode`\~\active
\catcode`\@=11
\def~#1{\let\@tempa=#1\afterassignment\tilde@\let\next= }
\def\tilde@{%
  \ifx L\@tempa
    \expandafter\tilde@@
  \else
    \tilde@aux
  \fi
}
\def\tilde@@{%
  \if\noexpand\next\@sptoken
    \expandafter\tilde@hide@or@show
  \else
    \tilde@aux
  \fi
}
\def\tilde@aux{\nobreakspace\@tempa\next}
\def\tilde@hide@or@show#1 L~{\ifnum\switch>0\unskip\else#1\fi}
\catcode`\@=12

\begin{document}
~L Hello L~ World~League
\end{document}

With \switch=0 it will compile to

output_0

and with \switch=1 to

output_1

Comment character approach

If you are willing to allow a different syntax the easiest way is to define another comment character along to the canonic one, i.e. %. Let's say the forward slash is our candidate:

\documentclass{article}

\def\hideon{\catcode`\/=14}
\def\hideoff{\catcode`\/=9}
\hideon

\begin{document}
/ Hello
World
\end{document}

Here \hideon and \hideoff are equivalent to \switch=1 and \switch=0 in the last examples.


Yet, you can mimic the last technique and have a version that comes a little closer to your planed syntax design by using the tilde version with a modified \tilde@hide@or@show (c.f. Active character approach) that expects only the initial "~L" and from than on scans unto the end of the line:

\def\tilde@hide@or@show{\begingroup\catcode`\^^M=12 \tilde@hide@or@show@}
\bgroup\catcode`\^^M=12 %
  \gdef\tilde@hide@or@show@#1^^M{%
    \ifnum\switch>0\unskip\else#1 \fi\endgroup}%
\egroup

~L then would be used as

~L Hello
World

The complete example:

\documentclass{article}

\newcount\switch
\switch=1

\catcode`\~\active
\catcode`\@=11
\def~#1{\let\@tempa=#1\afterassignment\tilde@\let\next= }
\def\tilde@{%
  \ifx L\@tempa
    \expandafter\tilde@@
  \else
    \tilde@aux
  \fi
}
\def\tilde@@{%
  \if\noexpand\next\@sptoken
    \expandafter\tilde@hide@or@show
  \else
    \tilde@aux
  \fi
}
\def\tilde@aux{\nobreakspace\@tempa\next}
\def\tilde@hide@or@show{\begingroup\catcode`\^^M=12 \tilde@hide@or@show@}
\bgroup\catcode`\^^M=12 %
  \gdef\tilde@hide@or@show@#1^^M{%
    \ifnum\switch>0\unskip\else#1 \fi\endgroup}%
\egroup
\catcode`\@=12

\begin{document}
~L Hello
World,~Hello
\end{document}
  • Could you please specify, where problems could arise, when I use your first solution, the active sequence approach but with { ? Could I receive errors when compiling, that arise from this change of the category code of {, when I use { in other parts of my document ? – l7ll7 Sep 2 '15 at 16:03
  • @user10324, because after the catcode change every grouping is done with parentheses, you have to call macros like \somemacro(...) and everything which assumes the original meaning of parentheses isn't usable anymore. (In other words: In my opinion it is an interface change that is too big and actual things break.) On the other, I think there might be a way to preserve the old behaviour of { and } (similar to the tilde version); have some ideas in mind that I'll test tomorrow -- stay tuned... – Ruben Sep 3 '15 at 0:07
  • @user10324 -- Updates added regarding your last question + a third approach and a merger of the second and third approach. – Ruben Sep 6 '15 at 11:33
  • Wow, you put so much work into this, wish I could upvote multiple time... – l7ll7 Sep 6 '15 at 12:26
  • @user10324 -- I really liked your question and I'd say the effort was worth/adequate in relation. Thank you anyways! :) Hope my answer(s) also helped you... – Ruben Sep 7 '15 at 23:17
4

The simplest is to use the concept of delimited macros: this is not widely documented in LaTeX manuals, but LaTeX is built upon the TeX macro language which allows this functionality.

However doing exactly as you want would be problematic (we don't want to change the catcode of the braces), thus, if you accept to delimit the optional part in the following style: blah blah blah \YY optional\ZZ blah then put in the preamble:

\newcommand\YY{}
\newcommand\ZZ{}
\long\def\YY #1\ZZ {}

Then the optional text will not appear. If you want it to show, just comment out the \long\def ... line. This will print blah blah blah optionalblah, if you want a space you should have in your file \YY optional \ZZ, or, you can rather than \newcommand\ZZ{} define \newcommand\ZZ{ }. Full mwe:

\documentclass{article}
\newcommand\YY{}
\newcommand\ZZ{}
% comment next line out to deactivate \YY and \ZZ
\long\def\YY #1\ZZ {}
\begin{document}
blah blah blah \YY optional\ZZ blah
\end{document}

This is a method for short pieces of text: for longer ones you might end up with the problem of nested \YY ... \YY .. \ZZ ... \ZZ which will not give the expected thing.

4

Here's a LuaLaTeX-based solution. It defines a Lua function, called hidedelims, that extracts the material surrounded by the delimiters " {L" and "L} ", and it sets up two LaTeX macros, called \switchon and \switchoff, that enable and disable the operation of the Lua function. The term "whitespace" is understood in its generic sense, i.e., to comprise not only space but also "tab" characters. (In Lua, %s denotes a generic whitespace character.)

Remark: The write-up of your requirements is a bit confusing. At first, you seem to state that everything between the pair of delimiters should be hidden. Later on, you seem to state that the material between the delimiters -- but not the delimiters themselves -- should, in fact, be shown. In my answer, I've implemented the second requirement. If you do want to hide all material between the delimiters (as well as, presumably, the delimiters themselves), just change the line

   return ( string.gsub ( line , '%s{L(.-)L}%s', '%1' ) )

to

   return ( string.gsub ( line , '%s{L.*L}%s', '' ) )

In the following screenshot, the vertical line to the left and the dot to the right of all instances of the strings " {LHelloL} " and " {LGoodbyeL} " are used to delimit visually the output that's produced when hiding the delimiters is either switched on or off. The \verb+ ... + macro is used to display the { and } characters (if not removed by hidedelims).

enter image description here

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

%% Lua-side code: A function called "hidedelims"
\usepackage{luacode}
\begin{luacode}
function hidedelims ( line )
   return ( string.gsub ( line , '%s{L(.-)L}%s', '%1' ) )
end
\end{luacode}

%% TeX-side code: Macros to enable/disable the Lua function
\usepackage{luatexbase}
\newcommand\switchon{\directlua{%
    luatexbase.add_to_callback ( "process_input_buffer",
                                 hidedelims, "hidedelims" )}}
\newcommand\switchoff{\directlua{%
    luatexbase.remove_from_callback( "process_input_buffer",
                                     "hidedelims" )}}

%% Just for this example...
\usepackage{showframe}
\setlength\parindent{0pt}

\begin{document}
\verb+ {LHelloL} +.

\switchon
\verb+ {LHelloL} +.

\switchoff
\verb+ {LHelloL} +.


\medskip
\verb+ {LGoodbyeL} +.

\switchon
\verb+ {LGoodbyeL} +.

\switchoff
\verb+ {LGoodbyeL} +.    
\end{document}


Here's a version of the code that always hides the delimiters, and either shows or hides the material within the delimiters, depending on whether \HideOff or \HideOn is in effect. The following screenshot shows the result of two passes -- first with \HideOff, then with \HideOn -- over a paragraph that contains material delimited by {L and L}.

enter image description here

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

%% Lua-side code:
%% - Boolean variable "check_hide_stuff"
%5 - Function "hide_stuff", assigned to "process_input_buffer" callback
\usepackage{luacode,luatexbase}
\begin{luacode}
check_hide_stuff = false
function hide_stuff ( line )
  if check_hide_stuff then
    return ( string.gsub ( line , '%s{L.-L}%s', '' ) )
  else
    return ( string.gsub ( line , '%s{L(.-)L}%s', '%1' ) )
  end
end
luatexbase.add_to_callback ( "process_input_buffer",
                hide_stuff, "hidestuff" )
\end{luacode}

%% TeX-side code: Macros to modify value of "check_hide_stuff"
\newcommand\HideOn{\directlua{check_hide_stuff = true}}
\newcommand\HideOff{\directlua{check_hide_stuff = false}}

\begin{document}
\HideOff %% show material inside delimiters

\noindent
A long time ago {L in a galaxy far, far awayL} , a {L beautifulL}  princess lived in a  {LmajesticL}  castle close to a  {Lmysterious andL}  dark forest {LL} .

\HideOn %% hide material inside delimiters

\bigskip\noindent
A long time ago {L in a galaxy far, far awayL} , a {L beautifulL}  princess lived in a  {LmajesticL}  castle close to a  {Lmysterious andL}  dark forest {LL} .

\end{document}
  • Thanks for your Lua-based answer (the delimiter themselves also have to be removed - it was nice you also provided a solution for that case). It is actually one I like a lot as I don't have to change { to some other character - but I have to get acquainted with Lua for that first. I yet have to see, how well that works – l7ll7 Sep 2 '15 at 16:21
  • @user10324 - Glad you found my answer useful. LuaLaTeX is a superset of pdfLaTeX; all documents that compile correctly under pdfLaTeX should compile correctly (apart possibly from some simple adjustments) under LuaLaTeX as well. To me, one of the very nice things about LuaLaTeX is that provides not only all the capabilities of pdfLaTeX but also gives access to a modern scripting language. If you haven't already done so, you may want to read the posting, The differences between TeX engines, for more information about the various TeX engines. – Mico Sep 2 '15 at 17:26
  • This is a great link, you gave me!! – l7ll7 Sep 4 '15 at 12:43
  • @user10324 - As I noted in my answer, I was (am still am, unfortunately) confused about your exact objective. Is it met adequately by my answer, or are you looking to having a system by which you can either show the delimited material if "switch=on" or hide the delimited material if "switch=off"? Please advise. – Mico Sep 4 '15 at 15:13
  • Isn't your code doing exactly that, i.e. doesn't your code either shows the delimited material if \switchon is inserted or hides the delimited material if \switchoffis inserted ? That is exactly want I wanted (although I still have to get to gripes with LuaLaTex). That \switchon is used instead of, e.g., a piece of code like switch=on, is only a cosmetic difference, if I'm not missing something here. – l7ll7 Sep 4 '15 at 16:55
2

You can replace "{L " by \hideBEG and " L}" by \hideEND by encTeX's primitive \mubyte. Then the removing the argument is a simple TeX task:

\mubyte\hideBEG {L \endmubyte              % "{L " -> \hideBEG
\mubyte\hideEND \space\space L}\endmubyte  % " L}" -> \hideEND

\newcount\switch    \switch=0

\ifnum\switch>0
   \def\hideBEG #1\hideEND{\unskip}
\else
   \def\hideBEG #1\hideEND{#1}
\fi

This is test {L word L} here.

\end

EncTeX is a simple preprocessor built in pfdTeX, but LaTeX doesn't activate it by default. It must be activated during format generation. For example, csplain format activates encTeX by default, so my example can be tested by csplain format (no LaTeX).

  • This is an interesting answer, very promising by its simplicity, I have to document myself a bit about encTeX, I didn't knew about it. Reading on CTAN about encTeX, I am a bit confused: What is the difference between encTeX and, say, LuaTeX ? Both append three letter in front of "TeX", so I thought both were variants of "TeX", but encTeX seems to rather be a package for TeX. It says encTeX is "an extension of TeX". How is this extension different from standard LaTeX ? (Sorry that I know so little about these things and have to ask around, because documentation can be very technical.) – l7ll7 Sep 2 '15 at 16:29
  • @user10324 TeX binary (or engine) is able to interpret macro language. LaTeX was macro package for TeX. Now, classical Knuth's TeX binary is used very rare, but there are many extensions built into the binary: pdfTeX (micro-typography, PDF output), eTeX (new primitives, it is part of pdfTeX), encTeX (it is part of pdfTeX), XeTeX and LuaTeX (great extensions projects). LaTeX needs eTeX today, i.e. it needs the pdfTeX binary where eTeX is its part. But still LaTeX is macro package over pdfTeX (or XeLaTeX over XeTeX or LuaLaTeX over LuaTeX) with many many sub-packages written at macro level. – wipet Sep 2 '15 at 17:09
  • I spent some time (although, I confess, not too much) on the internet trying to figure out how to activate enctex. could you please help me ? – l7ll7 Sep 4 '15 at 16:59
  • @user10324 Use -enc option when .fmt format is generated. Typically pdftex -ini -enc format.ini generates format.fmt. When such format is used then encTeX is enabled. Unfortunately, the format generation process, the storing generated formats and using them is TeX distribution and operating system dependent issue. – wipet Sep 4 '15 at 18:18
  • Sorry to come back to this topic after almost two month, but back then I didn't had the time to work all of this compilation stuff out, because time was pressing and a solution was needed fast. But now I have some time and again read through the answer and tried to compile it and still couldn't do it: when I save the above text in a tile.tex and then use pdftex -ini -enc file.tex it will give me an error ! Undefined control sequence. l.2 \mubyte\hideEND \space \space L}\endmubyte % " L}" -> \hideEND. The error seems to be due to [...] – l7ll7 Nov 3 '15 at 11:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.