Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

With the commands \openout and \write I output text into a file. How can i output a tab ?

\documentclass{article}
\begin{document}
  \newwrite\tempfile
  \immediate\openout\tempfile="filename.txt"
  \immediate\write\tempfile{I want a tab at the beginning of this line}
  \immediate\closeout\tempfile
\end{document}

EDIT1

Following egreg's solution, i use \catcode\^^I=12`. This works if i use directly the code, but not if i enclose the code in a command :

\documentclass{article}
\begin{document}
      \newwrite\tempfile
      \immediate\openout\tempfile="filename.txt"
      \begingroup
        \catcode`\^^I=12 %
        \immediate\write\tempfile{^^II want a tab at the beginning of this line}
      \endgroup
      \immediate\closeout\tempfile

    \newcommand{\test}{
    \newwrite\tempfilee
    \begingroup\catcode`\^^I=12 %
    \immediate\openout\tempfilee="filename2.txt"
        \immediate\write\tempfilee{^^II want a tab at the beginning of this line}
    \endgroup
    }

    \test   
    coucou
\end{document}

EDIT2 . Thanks again to egreg. The 2nd solution works, but not if i call \test from inside another command, which is what i need :

\newwrite\tempfile
\immediate\openout\tempfile=\jobname.out

\def\test{\begingroup\catcode`\^^I=12 \testaux}
\def\testaux#1{\immediate\write\tempfile{#1}\endgroup}

\newcommand{\makeit}{
\test{^^I<-TAB again}
}

\test{        <-TAB} % WORKS
\test{^^I<-TAB} %WORkS
\makeit %DOES NOT WORK
\immediate\closeout\tempfile

EDIT 3. The second solution of egreg works ... but not if it is inside a AtEndDocument :

\documentclass{article}
\AtEndDocument{\test{^^Ifin du document}
\immediate\closeout\tempfile }

\begin{document}
\newwrite\tempfile
\immediate\openout\tempfile=output.txt
\catcode`\^^I=\active
\def^^I{}
\def\test#1{\begingroup
\edef^^I{\string^^I}\immediate\write\tempfile{#1}\endgroup}

\test{^^I<-coucou} %% WORKS
\def\foo{\test{^^I<-Jojo}}
\foo  %% WORKS
\end{document}

But the last sentence "fin du document" has no TAB.

share|improve this question
    
I beleive it is the ^^I character. Albeit I can give it as an answer I would like to be more generic in my answer, which I am not that good at yet. :) –  zeroth Jun 6 '12 at 7:19
    
i tested, but it does not seem to work. –  nicolas roy Jun 6 '12 at 7:24
add comment

2 Answers 2

up vote 9 down vote accepted

Writing a literal TAB character in a file is, unfortunately, dependent on the TeX distribution you have and how the formats were initialized.

With a TeX Live distribution, the formats for pdftex, pdflatex and latex are prepared feeding the option -translate-file=cp227.tcx, that makes the TAB character "printable".

Compiling the input

\newwrite\tempfile
\immediate\openout\tempfile=\jobname.out
\begingroup
  \catcode`\^^I=12 %
  \immediate\write\tempfile{^^I<-TAB}
\endgroup
\immediate\closeout\tempfile
\csname @@end\endcsname\end % trick for stopping with Plain TeX and LaTeX

with tex and with pdftex (on a TeX Live distribution) will produce two different results (I report the "hex dump"):

  1. 5e 5e 49 3c 2d 54 41 42 0a (tex)

  2. 09 3c 2d 54 41 42 0a (pdftex)

Indeed tex is not set up with the TCX translation that makes the TAB character printable.

If one compiles the file with luatex or lualatex the result will be as in case 2. With xetex it's still different.

  1. 5e 5e 49 3c 2d 54 41 42 0a (xetex)

  2. 09 3c 2d 54 41 42 0a (xetex -8bit)

Thus the ^^I is written in this form with tex, xetex or xelatex, while it is written as a literal TAB with pdftex, pdflatex, luatex or lualatex, but also with xetex and xelatex provided they are called with the -8bit option.

The moral of the story is: don't use TABs and don't try writing them in files, for the result won't be predictable across systems and machines.


How to define a command that writes a line to a file respecting the TAB characters (assuming pdftex)?

One has to remember that the category codes are fixed once a token list has been read in by TeX. So one has to use a different strategy:

\newwrite\tempfile
\immediate\openout\tempfile=\jobname.out

\def\test{\begingroup\catcode`\^^I=12 \testaux}
\def\testaux#1{\immediate\write\tempfile{#1}\endgroup}

\test{        <-TAB}
\test{^^I<-TAB}

\immediate\closeout\tempfile

\csname @@end\endcsname\end

This will write in \jobname.out (again showing the hex dump)

09 3c 2d 54 41 42 0a 09 3c 2d 54 41 42 0a

so two literal TABS (the space in the first argument to \test is supposed to be a TAB, which on this system may be converted to spaces, unfortunately) are written.


If you need \test to work also in the argument to another command, then the trick above won't work: something like \foo{x \test{^^I<-TAB}}, where \foo takes one argument, would defeat the delayed grabbing of the argument done in \testaux rather than in \test: when TeX stores the argument to \foo it fixes the category codes.

However there's another problem: TeX normalizes ^^I to a space token as soon as it reads it (when ^^I has category code 10). So your problem is much more difficult to solve. If you don't need the TAB in your file other than for the purpose of writing it, you can do

\catcode`\^^I=\active
\def^^I{}

\newwrite\tempfile
\immediate\openout\tempfile=\jobname.out

\def\test#1{\begingroup
  \edef^^I{\string^^I}\immediate\write\tempfile{#1}\endgroup}

\test{        <-TAB}
\test{^^I<-TAB}

\def\foo#1{#1\test{#1}}

\foo{^^I<-TAB}

\immediate\closeout\tempfile

\csname @@end\endcsname\end

This has the limitation that the TAB won't print anything and a sequence <SPACE><TAB><SPACE> will print two spaces.

Consider very well not to proceed along this path.

If the commands where \test is needed are limited in number, one might proceed as in the case above giving a correct definition. If you want to allow \test as the argument to any command, you're out of luck.


If all you need is to do a write \AtEndDocument, you can say

\begingroup
\catcode`\^^I=12
\gdef\EndTest{\test{^^I<-TAB}}
\endgroup
\AtEndDocument{\EndTest}

One could do without defining a new command:

\begingroup
\lccode`?=`\^^I
\lowercase{\endgroup\AtEndDocument{\test{?fin du document}}}
\AtEndDocument{\immediate\closeout\tempfile}

You can use a different character than ?, what's important is that it's a category 12 character.

share|improve this answer
    
well, i understand the potential problems, but I need it, and i will use it always with pdftex. A biggest problem for me is : when i put your code in a command \test and i call \test, then the TAB is replaced by an empty space in the output file. Why ? –  nicolas roy Jun 6 '12 at 9:33
    
You need to define \test in a context where ^^I already has category code 12. Please, update your question. –  egreg Jun 6 '12 at 9:39
    
i think a #1 ist missing in the def of \testaux, isnt it ? or maybe, i just do not understand the code... :( –  nicolas roy Jun 6 '12 at 13:15
    
ok, i think i got it. Anyway, it works :) Great ! –  nicolas roy Jun 6 '12 at 13:21
    
just to check wether i understood or not : if we put a #1 in the definition of ţextaux, it does not work anymore, because somehow, the replacement text of #1 ist expanded too early. Is it correct ? –  nicolas roy Jun 6 '12 at 13:25
show 5 more comments

You may define a new macro \mytab providing the TAB character with category 12.

\begingroup
\catcode`\^^I=12
\gdef\mytab{^^I}
\endgroup

Then, use \mytab (with a space at end) instead of ^^I or <TAB>:

\documentclass{article}
% memoize TAB char
\begingroup
\catcode`\^^I=12
\gdef\mytab{^^I}
\endgroup
% open temp file
\newwrite\tempfile
\immediate\openout\tempfile=\jobname.out
% macro to write to temp file
\def\writetotemp#1{\immediate\write\tempfile{#1}}

\AtEndDocument{\writetotemp{\mytab<-TABEND}}
\AtEndDocument{\immediate\closeout\tempfile}
\begin{document}
\immediate\write\tempfile{\mytab <-TAB1}
\writetotemp{\mytab <-TAB2}
\end{document}

Here is the dump of \jobname.out:

0000000  \t   <   -   T   A   B   1  \n  \t   <   -   T   A   B   2  \n
           3c09    542d    4241    0a31    3c09    542d    4241    0a32
0000020  \t   <   -   T   A   B   E   N   D  \n
           3c09    542d    4241    4e45    0a44
0000032
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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