3

I would like to define two switches such that this code

\begin{document} \A This is text A Some more text A \B some text B \A again some text A \end{document} 

produces the following output:

This is text A Some more text A again some text A 

if switch A is active and B is not,

some text B 

if switch B is active and A is not, and

This is text A Some more text A some text B again some text A 

if both are active. I'd like the syntax in the document to be exactly as described, in particular without braces {} and without extra commands.

Edit: Comments suggested I give MWE instead of this vague description of my ideas. Here they are: (all should output A1 A2)

  1. Using \defs and arguments. Does not work (I believe) because first \A eats everything until last \Z, so \B has no \Z.
\documentclass{article} \def\Z{} \long\def\A#1\Z{\Z#1} \long\def\B#1\Z{\Z} \begin{document} \A A1 \B B1 \A A2 \B B2 \Z %would be hidden in a new def of \end{document} \end{document} 
  1. Using \ifs. Does not work (I believe) because the iffalse in \B eats everything until last \fi, and the \fi in \A is not expanded.
\documentclass{article} \def\A{\fi\iftrue} \def\B{\fi\iffalse} \begin{document} \iftrue %would be hidden in a new def of \begin{document} \A A1 \B B1 \A A2 \B B2 \fi %would be hidden in a new def of \end{document} \end{document} 
  1. Using \NewDocumentEnvironment. Does not work, but I'm not sure why. The first \A seems to expand fine, but the first \B seems to eat everything until last \end{myenv}.
\documentclass{article} \NewDocumentEnvironment{myenv}{+b}{#1}{} \newcommand{\A}{\end{myenv}\RenewDocumentEnvironment{myenv}{+b}{##1}{}\begin{myenv}} \newcommand{\B}{\end{myenv}\RenewDocumentEnvironment{myenv}{+b}{}{}\begin{myenv}} \begin{document} \begin{myenv} %would be hidden in a new def of \begin{document} \A A1 \B B1 \A A2 \B B2 \end{myenv} %would be hidden in a new def of \end{document} \end{document} 

OLD: Here were my ideas so far:

  1. Use conditionals: Set \A to \iftrue and \B to \iffalse in the preamble. Something like \def\A{\fi\iftrue} \def\B{\fi\iffalse}. I can then redefine the document env to start with \iftrue and end with \fi. The problem is: the \iffalse skips over every token until \fi, even if it expands to \fi... And I don't want to have to type something like \fi\B!
  2. Define \A and \B as commands that take as argument everything until the next \A or \B (Something along the lines of \def\Z{} \def\A#1\Z{\Z#1} \def\B#1\Z{\Z#1}) I can then redefine one or the other to output #1 or nothing, if I want text A or not. The problem is (I can't seem to get it to scan past \par without braces...) Edit: this works now (see comments). The problem is that the token \Z coming from \B is not expanded, and never seen by the argument scanning of \A... I'm not really as fluent in TeX as I'd like to be, so perhaps I missed something obvious. I welcome any alternative!
13
  • 1
    “I can't seem to get it to scan past \par” Try \long\def instead of \def. Commented Jul 4 at 6:40
  • Indeed you're right, the problem is not the \par (it works with \long\def). Thanks! The problem is actually that the closing \Z token is not seen (as, I suppose, \B is not expanded) Commented Jul 4 at 7:07
  • "I'd like the syntax in the document to be exactly as described" I think you'll have a hard time with that. But why this constraint? Why not have one command with an argument? That would be much easier to implement. E.g. you could write \ifactive A and \ifactive B, or if you prefer \ifactive1 and \ifactive2. Commented Jul 4 at 8:48
  • welcome! (1) please provide a complete example for a minimal document which can be compiled to produce the error. snippets are not useful for testing, especially when your question turns on how you've defined things included in the missing parts. (2) when tex finds an \if, it scans until it finds the matching \fi without expanding macros in between, as I understand it. so you cannot hide the \fi in the definition of a macro unless you ensure that macro is expanded first. Commented Jul 4 at 9:36
  • 1
    not sure why you want this syntax, but if it is to save time/typing, any time you save will be more than outweighed by the time you have to spend searching for mistakes in your document. if you ever write \A without the terminating B or whatever, you will get no error until the end of document. and you will get no help from your latex editor in terms of highlighting argument deliminaters etc. for short pieces of text, it is not so bad because you get an error at the next \par, but for long ones it is a pain even when the \fis aren't obfuscated like this. Commented Jul 4 at 9:56

1 Answer 1

3

Disclaimer: I don't recommend this. I wouldn't do it. I wouldn't let my cat do it. I am not responsible (morally, legally, causally) if your computer explodes in protest, your cat abandons you for a ship and the wrath of the gurus falls upon your head. This will cause you headaches unless used in extremely limited fashion. No warranties are offered, implied, proffered, suggested or provided. Not even headaches. You have been amply warned.

Caveat emptor


If I could have done this by peeking ahead, I would, but that Cis entirely beyond me. On the other hand, this is probably safer.


You cannot hide \fi or the end of an environment in a macro (including a macro which defines an environment). When TeX sees \if it scans to the matching \fi without expanding the stuff between. If the \fi is hidden, it hits the end of the file first.

Either you need to parse the input token stream bit by bit yourself or you need to delimit the input in some way e.g. by putting it into an argument or environment.

So you could, for example, do this:

\documentclass{article} % ateb: https://tex.stackexchange.com/a/747242/ \ExplSyntaxOn \makeatletter \@ifl@t@r\ExplLoaderFileDate{2024-12-08}{ }{% if latex is too old, supply the missing functions we need \cs_new_protected:Npn \tl_regex_replace_once:Nnn #1#2#3 { \regex_replace_once:nnN {#2} {#3} #1 } \cs_new_protected:Npn \tl_regex_replace_all:Nnn #1#2#3 { \regex_replace_all:nnN {#2} {#3} #1 } } \makeatother \keys_define:nn { usertwo } { A .bool_set:N = \l_usertwo_a_bool, B .bool_set:N = \l_usertwo_b_bool, A .initial:n = false, B .initial:n = false, A .default:n = true, B .default:n = true, } \cs_new_protected:Npn \__usertwo_a:n #1 { \bool_if:NT \l_usertwo_a_bool { #1 } } \cs_new_protected:Npn \__usertwo_b:n #1 { \bool_if:NT \l_usertwo_b_bool { #1 } } \tl_new:N \l_usertwo_iffy_tl \NewDocumentEnvironment{iffy}{o+b} { \IfValueT { #1 } { \keys_set:nn { usertwo } { #1 } } \__usertwo_iffy:n { #2 } }{} \cs_new_protected:Npn \__usertwo_iffy:n #1 { \tl_set:Nn \l_usertwo_iffy_tl { #1 } \tl_regex_replace_once:Nnn \l_usertwo_iffy_tl { \c{A} (.*) \Z } { \c{__usertwo_a:n} \cB\{ \1 \cE\} } \tl_regex_replace_all:Nnn \l_usertwo_iffy_tl { \c{A} } { \cE\} \c{__usertwo_a:n} \cB\{ } \tl_regex_replace_all:Nnn \l_usertwo_iffy_tl { \c{B} } { \cE\} \c{__usertwo_b:n} \cB\{ } \l_usertwo_iffy_tl } \NewDocumentCommand \usertwoset { m } { \keys_set:nn { usertwo } { #1 } } \ExplSyntaxOff \pagestyle{empty} \usertwoset{A} \begin{document} \section{A} \begin{iffy} \A This is text A Some more text A \B some text B \A again some text A \end{iffy} \section{B} \begin{iffy}[B,A=false] \A This is text A Some more text A \B some text B \A again some text A \end{iffy} \section{A\&B} \begin{iffy}[A,B] \A This is text A Some more text A \B some text B \A again some text A \end{iffy} \end{document} 

This is not quite the requested syntax, but it is significantly safer.

I refuse to suggest ways of redefining \begin{document} and \end{document} but you could do something like

\hook_gput_code:nnn {begindocument/end} {usertwo} { \begin{iffy} } \hook_gput_code:nnn {enddocument} {usertwo} { \end{iffy} } 

and then write

\begin{document} \section{A} \A This is text A Some more text A \B some text B \A again some text A \end{document} 

if your document is not too long. I recommend this still less than explicit use of the environment as it makes it much harder for a reader to understand your code. (That reader will likely be you.)

8
  • Wow thanks a lot!! I realy appreciate you giving an answer, despite the danger involved for the user :) At the moment, I can't compile it (it complains that \l_usertwo_iffy_tl is not defined), but I must be doing something wrong - I'm really unfamiliar with Latex3. I'll try again tomorrow. Thanks a lot! Commented Jul 4 at 18:25
  • @user2026844 it should compile as that is defined. did you paste the code into an empty (new) document and compile it just as-is? you didn't alter it? if so, post the log. Commented Jul 4 at 18:31
  • @user2026844 for the environment case: tinyurl.com/yufsnfet and for the hook case: tinyurl.com/2hvm7ss8 (these are links to david carlisle's web interface for running latex examples. you can view the pdf inline below the source.) Commented Jul 4 at 18:39
  • 1
    I've copy pasted your first code block in my editor, as well as in overleaf - I get the same error. Here is the log ` stackexchange-answer.tex:55: Undefined control sequence. __usertwo_iffy:n ...1}\tl_regex_replace_once:Nnn \l_usertwo_iffy_tl {\c {A}... l.55 \end {iffy} The control sequence at the end [...] stackexchange-answer.tex:55: Undefined control sequence. \l_usertwo_iffy_tl ->\A This is text A \par Some more text A \B some text B ... l.55 \end {iffy}` and 5-10 more like this Commented Jul 5 at 7:22
  • @user2026844 oh. for your own system, you could update your tex distribution. but not for overleaf. see above for a version which should work on overleaf as well as a current install. if you followed my links, you'd see that the original code works fine on the latter. but two of the functions I used were added in 2024-12 and overleaf won't have those yet. Commented Jul 5 at 10:42

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.