1

I'm trying to write an expanded macro to a file without the expansion eating the space after it.

I could replace the {} empty group with an explicit \space, but I want this to be fairly robust. Is this possible to do?

I'm guessing since TeX never gets to the layout portion of the process, it doesn't know what to do with the unexpandable {} tokens, which is why they show up during the \write?

Example

% tex test.tex
\def \test {Hello}
\openout 0 hello.txt
\write 0 {\test{} World}
\end

Contents of hello.txt

Hello{} World

Expected

Hello World

Background

In broad strokes, this project is trying to retrofit a sort of note/cross-reference system to a large document with many macros and edited by many people.

...
\def\proj{Foobar}
\def\rev{1.0}
\def\revstr{\proj{} v\rev}
\def\complicated{...} % essentially a bunch of ifs and concats
... % A bunch of macros scattered throughout
Body of document contains macros like \proj{} and \revstr. 
The definitions of these macros are tweaked and modified.
... % A bunch of text with \notes scattered throughout,
    % also tweaked/modified, added/removed
\note{Used for callouts to \proj{} and whatever else}
...

The notes are currently typeset with the document, and the task is to also put them into a file for processing by an external program. For the vast majority of cases, callouts just have text and macros: no formatting or anything that couldn't be represented in ASCII.

Manually going through all the macros to replace {} with \space is somewhat out of the question, due to the volume and going against the established workflow.

The fallback is just post-process the file once TeX is done with it. Seems like the ham-fisted approach though, since TeX has all the information necessary to boil down the text.

Maybe there is a way to pretend layout a page, but then strip the content out of the boxes and put it into a file?

7
  • Welcome! What is wrong with an explicit \space?
    – user194703
    Nov 8, 2019 at 6:04
  • It's a more fragile solution. Say I did use \space, but then \test changed to include a macro expansion itself, like \greeting{} friend. The same problem would come up again and that would need to be replaced with \space too. TeX seems happy with the \test{} convention in other places, would be nice if it could work in this scenario as well. I'm looking to use some macros like this in multiple places in the document (in addition to writing to file). Nov 8, 2019 at 6:17
  • @TeXhnicallyChallenged \space is the choice for the business. However, it's hard to tell what your real aim is. Can you please be a bit more explicit about your project? Small “Hello world” examples are good, but not for describing complex tasks.
    – egreg
    Nov 8, 2019 at 7:55
  • @egreg Added a bit of background. Hopefully that gives more insight into the project. Nov 8, 2019 at 9:14
  • It is almost always best when asking here not to post disconnected fragments but to post a small self contained test file that shows the issue and can be used to test answers, although I've attempted an answer below without such a test file. Nov 8, 2019 at 9:48

1 Answer 1

1

Using {} in a write will produce {} that is the expected effect.

You could use \space It's not clear why you expect the normal TeX tokenization not to apply here since you are expecting \test to be tokenized and expanded as normal. If that was not the case, you could use

\write20{\noexpand\test zzz}

which would write \test zzz

But if you want \test to expand then

\write20{\test\space zzz}

is the simplest solution, although there areothers which can be useful sometimes, such as

\def\zz#1{\write20{\test#1zzz}}\zz{ }

which puts a space token, rather than \space which expands to a space token into the argument of \write.

You could also (and might be what you want here) treat space tokens verbatim not as normal TeX spaces so

{\catcode`\ =12\relax% space is a normal punctuation character
\write20{\test zzz}%
}% back to normal
5
  • "It's not clear why you expect the normal TeX tokenization not to apply"-- Because I don't understand what \write is doing, nor the tokenization rules :) These are the sort of black magic tricks I thought might exist, however they don't quite work if \test is something like \foo{} bar Nov 8, 2019 at 17:29
  • @TeXhnicallyChallenged that is the same issue: you would need to write \foo\space bar for the same reason. Nov 8, 2019 at 17:50
  • @TeXhnicallyChallenged or define all your macros with arguments, if \foo is defined by \newcommand\foo[1]{I don't use the argument} then \foo{} bar will be I don't use the argument bar Nov 8, 2019 at 17:53
  • The problem with the fake argument is that it will eat a token if the user intended there not to be a space. It also won't work if the user has \foo\ bar. I'm trying to avoid changing the input macros, if possible. Nov 8, 2019 at 18:01
  • @TeXhnicallyChallenged if you have input that doesn't work, you need to change something, given the standard definitions the input is wrong (misusing {} if the text isn't being typeset) so you need to either change the input and use \space or change the definitions so that {} is removed. Nov 8, 2019 at 18:35

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.