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.

I would like to ask something which will greatly facilitate my work. But before, I introduce you to the problem I face. In my attempt to gather my notes for my students and give them something more quality like a book I've created hundreds of exercises where each one is a small own file. I input those through \input{...}.

The problem I face is that I have in the first 2 or 3 lines of each separate file certain information such as, source of exercise, as the name of the file in which the exercise is, etc. That information I do not want to appear in the final result, so I comment those out with %. Occasionally, however, as I still processing the text I want to appear these private information I have on the first lines on each separate file. As you can imagine being open about 500+ files and make comment out % the fist and second lines and after the inverse is somewhat painful.


Here's my question: Is there inner way to Latex to read a file that is imported but ignore the first two maybe three lines that have not been comment out with % ? Of course this could be done with a scrip from the command line by adding % in front of firsts lines ( Ι working on Linux) but what was very elegant and easy to do with some internal switch to LaΤeΧ . So I can choose when the first lines will appear and when not.


one example of how I structured each exercise

\\ {\color{red}{\small is the  exercise.435.tex}}  % is the name of the file
\\ {\color{red}{\small 1.84 ex. 127 page notes}}  % is the source of exercise etc

\begin{exercise}    
. . . 
\end{exercise}

Final With your help and after two days.

I have collect here the final form I used eventually. I've added the automatization of detection exercises's names . Perhaps new users of latex as me , find something useful

( I wrote here because I didn't know the right place to write those thinking. if is there another option please let me know )

\documentclass[a4paper,10pt]{article}
\usepackage{xcolor}

\usepackage[realmainfile]{currfile}[2012/05/06] % detects the names of imported files

%%%%%%%%%%%%%%%%%%%%%%%%%% for prologue ( The code is from the @egreg ) %%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newif\ifprolog  
\long\def\startprolog#1\stopprolog{%
  \ifprolog
    \par
    \begingroup
    \let\\\par
    \color{red}\small \\  \currfilepath \\ #1    % \currfilepath for appear the name of each exersice is my extra  addition 
    \par\medskip                          
    \endgroup                                 
  \fi}

\prologtrue % for to display the prologue ( comment out to disappear )

%%%%%%%%%%%%%%%%%%%%%%%%%% definition of exercise %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newtheorem{exercise}{\color{magenta} \Large \bfseries} % [chapter]    %[section]   %% at the book documentclass 


\begin{document}

 text above the exercise

 \input{exersice.435.tex}

 Text below the exercise

 \end{document}

and the external file exersice.435.tex have the form:

\startprolog
  1.84 ex. 127 page notes   % is the source of exercise etc
\stopprolog

\begin{exercise}
 Here is the text of the exercise
\end{exercise}

the final result

share|improve this question
add comment

5 Answers

up vote 10 down vote accepted

If your input files all have the same form, that is some lines starting with \\ and an empty line after them, you can do by temporarily redefining \\ and changing the command for inputting the exercises:

\newcommand{\exeinput}[1]{%
  \let\latexdoublebackslash\\
  \ifprolog\let\\\showprolog\else\let\\\hideprolog\fi
  \input{#1}}

\def\showprolog#1\par{%
  \def\\{\par\noindent}% redefine `\\` to end lines
  \par\noindent
  #1% print the lines
  \par % end the last line
  \let\\\latexdoublebackslash}

\def\hideprolog#1\par{\let\\\latexdoublebackslash} % throw away the prolog lines

\newif\ifprolog

So you can say

\exeinput{exercise.435.tex}

and if you set \prologtrue also the prolog lines will be printed.

However this would spectacularly fail if there's not an empty line between the prolog and the main contents, so a special markup is probably the best strategy. For instance, if your exercise files have the form

\startprolog
\\ is the  exercise.435.tex % is the name of the file
\\ 1.84 ex. 127 page notes  % is the source of exercise etc
\stopprolog

\begin{exercise}    
. . . 
\end{exercise}

you can say

\newif\ifprolog
\long\def\startprolog#1\stopprolog{%
  \ifprolog
    \par
    \begingroup
    \let\\\par
    \color{red}\small #1
    \par\medskip
    \endgroup
  \fi}

and so

\input{exercise.435.tex}

will print the exercise without the prolog unless you set \prologtrue. The advantages are that you risk nothing if the prolog is not separated from the contents and that it's possible to reformat freely the prolog when you want to print it (maybe as a marginal note, for instance).

share|improve this answer
    
I also believe that it is more elegant to write my exercises in this way, with \startprolog \stopprolog –  karathan Oct 29 '12 at 10:24
    
Eventually I think I'll get in the process to enter in my files the \startprolog . . . \stopprolog. I think this will help me in the future as reported by @egreg. The problem of course is how I will make useful but this is is a different question and I will return in the future for that :-) –  karathan Oct 29 '12 at 21:46
add comment

LaTeX is a markup language. For the private information macros can be used. File exercise.435.tex could look like:

\private{is the \filename{exercise.435.tex}}
\private{1.84 ex.\@ 127 page notes}

\begin{exercise}
...
\end{exercise}

Then macro \private can be defined to set the contents in red and small font:

\newcommand*{\private}[1]{%
  \ifhmode\newline\fi
  \textcolor{red}{\small #1}%
  \ignorespaces
}%
\newcommand*{\filename}[1]{#1}% or \texttt{#1} or ...

And it is easy to suppress the lines:

\newcommand*{\private}[1]{\ignorespaces}

\ignorespaces removes the line end after \private{...} to avoid unwanted spaces.

share|improve this answer
1  
This still requires the editing of 500 files :) So I guess the optimal solution is to run a little sed script (ar something similar of your choice) on the existing files to insert this type of LaTeX macros for the first lines, and do it directly as you described for the next 500 ones :) –  Stefan Waldmann Oct 29 '12 at 6:52
    
@HeikoOberdiek Really good set of codes but needs to edit my 500+ files from the beginning and that's what I want to avoid :) –  karathan Oct 29 '12 at 7:03
1  
@StefanWaldmann Yes indeed a solution as I said in the beginning is to run a script. But I figured that maybe there is an internal solution in Latex :) –  karathan Oct 29 '12 at 7:08
3  
@karathan: If you are on Linux, you have tools at your disposal to automatically edit a group of files: sed as Stefan Waldmann pointed out, or gawk. For instance, sed -e 3~1p -e 's/\(.*\)/\\private{\1}/g' -n -e 1,2p exercise.435.tex > new.exercise.435.tex will enclose the content of the first two lines between \private{ and }, while leaving alone the remaining of the file. –  guillem Oct 29 '12 at 7:08
4  
A suggested improvement on the macro approach: Instead of coding everything as \private, use logical mark-up like \problemsource, \problemfilename, etc. You can then easily hide or show selected parts: \let each macro separately to either \private (hide it) or to a macro that shows it. @guillem's sed script can easily be modified to do this, if your headers have consistent structure. –  alexis Oct 29 '12 at 12:24
show 2 more comments

You could go the other way round, and change the catcode of % so that it no longer acts as comment char when you start reading the file. The exercise environment could then revert the change. You could also use some other (unused) char as special comment sign. But such catcode changes are a bit fragile, so it depends a lot on your document if the idea is usable:

\documentclass{article}
\begin{document}

\catcode`\%=9
% not ignored
% not ignored

\catcode`\%=13
\def%{\par Private: }
% not ignored
% not ignored

\catcode`\%=14
% ignored
% ignored
blub

\catcode`\@=14
@ ignored
@ ignored
exercise

\end{document}
share|improve this answer
add comment

I think this is a perfect job for LuaLaTeX. Maybe you want to give it a try.

\documentclass{article}
\usepackage{filecontents}

\begin{filecontents*}{testfile.tex}
1. line\\
2. line\\
3. line\\
4. line
\end{filecontents*}

\begin{filecontents*}{luaFunctions.lua}
function ReadFile(filename, skipFirstLines)
    -- open file
    local input = io.open(filename, 'r')

    -- read all lines and store them in a table
    lines = {}
    for line in input.lines(input) do
        lines[#lines + 1] = line
    end

    -- remove the first lines from table
    for i = 1, skipFirstLines do
        table.remove(lines, 1)
    end

    -- print the content of the table
    for k, v in pairs(lines) do
        tex.print(v)
    end
end
\end{filecontents*}    

\directlua{dofile("luaFunctions.lua")}

\def\readfile#1#2{\directlua{ReadFile("#1",#2)}}

\begin{document}
% \readfile{<filename>}{<count of lines to skip>}
\readfile{testfile.tex}{2}
\end{document}

Edit: Here is an example which extents the previous code with a loop to read a bunch of files at once.

\documentclass{article}
\usepackage{filecontents}

\begin{filecontents*}{exercise.1.tex}
1. line of exercise.1.tex\\
2. line of exercise.1.tex\\
3. line of exercise.1.tex\\
4. line of exercise.1.tex
\end{filecontents*}
\begin{filecontents*}{exercise.2.tex}
1. line of exercise.2.tex\\
2. line of exercise.2.tex\\
3. line of exercise.2.tex\\
4. line of exercise.2.tex
\end{filecontents*}
\begin{filecontents*}{exercise.3.tex}
1. line of exercise.3.tex\\
2. line of exercise.3.tex\\
3. line of exercise.3.tex\\
4. line of exercise.3.tex
\end{filecontents*}

\begin{filecontents*}{luaFunctions.lua}
function ReadFile(filename, skipFirstLines)
    -- open file
    local input = io.open(filename, 'r')

    -- read all lines and store them in a table
    local lines = {}
    for line in input.lines(input) do
        lines[#lines + 1] = line
    end

    -- remove the first lines from table
    for i = 1, skipFirstLines do
        table.remove(lines, 1)
    end

    -- print the content of the table
    for k, v in pairs(lines) do
        tex.print(v)
    end
end

function ReadFiles(startIndex, stopIndex, skipFirstLines)

    local counter = 0
    for i = startIndex, stopIndex do

        -- text before each exercise 
        counter = counter + 1
        local str = string.format("\\par\\vspace{2\\baselineskip}Exercise %s\\\\",counter)
        tex.print(str)

        -- create a filename an read the file
        local filename = exerciseFilenameBase..i..exerciseFilenameExtension
        ReadFile(filename, skipFirstLines)

    end
end

-- if needed change the filenames
exerciseFilenameBase = 'exercise.'
exerciseFilenameExtension = '.tex'
\end{filecontents*}

\directlua{dofile("luaFunctions.lua")}

\def\readfile#1#2{\directlua{ReadFile("#1",#2)}}
\def\readfiles#1#2#3{\directlua{ReadFiles(#1,#2,#3)}}

\begin{document}
% read a single file
%\readfile{<filename>}{<count of lines to skip>}
%\readfile{exercise.1.tex}{1}

% if the filenames are numbered consecutively, 
% one can input a bunch of files just with one command
%\readfiles{<number of first file to input>}{<number of last file to input>}{<count of lines to skip>}
\readfiles{2}{3}{2}
\end{document}
share|improve this answer
1  
I'm not sure I understand how I should write my exercises and how to call in my document. :) should instead \input to use \readfile{exercise.435.tex}{2} additional so far I use xelatex, does LuaLatex create some problem with the rest of the code on my document? –  karathan Oct 29 '12 at 10:00
1  
You are right, just use \readfile{exercise.435.tex}{2} instead of \input{exercise.435.tex}. That's all. There is no need to change your code. I don't think that you will run into big troubles if you switch from XeLaTeX to LuaLaTeX. But I don't know the rest of your tex files and the content of your exercises, so just try it. And if needed you can create a Lua function to read all exercise files in just one loop. –  Holle Oct 29 '12 at 12:46
    
o.k.thanks I will check it first at the whole text for possible crashes. "And if needed you can create a Lua function to read all exercise files in just one loop".....Sounds good but it should be a new question for that and I still have not cleared the previous :-) –  karathan Oct 29 '12 at 13:50
add comment

(I'm a bit nervous about posting another answer given the quality of the ones that have gone before ...)

This one works by looking at what you want to keep rather than what you want to throw away. It assumes that what you want is what's in between the \begin{exercise} ... \end{exercise}. It also assumes that you don't do anything fancy with catcodes in there so it is safe to slurp that into the body of a macro (using the environ package). We load the exercise file whilst within a box which is then thrown away, thus disposing of any additional junk whilst preserving the contents of the exercise to be reused immediately afterwards.

Obviously, I had to built a bit of example code so this might need adjusting for your particular situation. I'd say that the advantages are that you don't need to alter your existing files and it's robust with respect to their format: everything outside the exercise environment is simply chucked in the garbage box. However, it isn't robust if they do things like global assignments but I figured I was fairly safe in assuming that they didn't.

\documentclass{article}


\usepackage{xcolor}
\usepackage{filecontents}
\usepackage{environ}

\begin{filecontents*}{onlyexaux.tex}
\\ {\color{red}{\small is the  exercise.435.tex}}  % is the name of the file
\\ {\color{red}{\small 1.84 ex. 127 page notes}}  % is the source of exercise etc

\begin{exercise}    
This is an exercise.
You should do it carefully.
\end{exercise}
\end{filecontents*}

\newcounter{exercise}
\newenvironment{exercise}{%
  \begin{minipage}{.5\textwidth}%
  \refstepcounter{exercise}%
  \noindent\textbf{Exercise~\theexercise}\par}{\end{minipage}}

\newcommand{\getexercise}[1]{~\input{#1}}

\newif\ifprivate
\privatetrue
\ifprivate
\else

\let\oexercise=\exercise
\let\endoexercise=\endexercise
\let\exercise=\relax
\let\endexercise=\relax
\newbox\exbox
\NewEnviron{exercise}{%
  \global\let\currentexercise=\BODY
}

\renewcommand{\getexercise}[1]{%
  \setbox\exbox=\hbox\bgroup \input{#1}\egroup
  \begin{oexercise}%
  \currentexercise%
  \end{oexercise}%
}

\fi
\begin{document}

\getexercise{onlyexaux}

\end{document}

At the moment, the switch is the \privatetrue line in the main file. Obviously, that could be hidden a bit more neatly.

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.