# How to more efficiently get code like this?

I have a folder containing files like these,

2007.pdf
2007_Q1.pdf
2007_Q10.pdf
...

2007_Q5.pdf
2007_Q6.pdf
2007_Q7.pdf
2007_Q8.pdf
2007_Q9.pdf
2008.pdf
2008_Q1.pdf
2008_Q10.pdf
2008_Q11.pdf
2008_Q12.pdf
2008_Q13.pdf
2008_Q14.pdf
2008_Q15.pdf
2008_Q16.pdf
2008_Q17.pdf
2008_Q18.pdf
2008_Q19.pdf
2008_Q2.pdf
2008_Q20.pdf
2008_Q21.pdf
2008_Q22.pdf
2008_Q23.pdf
2008_Q24.pdf
2008_Q25.pdf
2008_Q3.pdf
...
...
2008_Q6.pdf
2008_Q7.pdf
2008_Q8.pdf
2008_Q9.pdf
...
...


I also have an Excel file which I can filter through these questions by topic. So I get lists like this easily,

2006    Q7
2006    Q24
2007    Q11
2007    Q24
2009    Q17
2009    Q23


for each topics. Then I use Notepad++ to get

\includegraphics[scale=0.9]{2006_Q7} \\[2ex]
\includegraphics[scale=0.9]{2006_Q24} \\[2ex]
\includegraphics[scale=0.9]{2007_Q11} \\[2ex]
\includegraphics[scale=0.9]{2007_Q24} \\[2ex]
\includegraphics[scale=0.9]{2009_Q17} \\[2ex]
\includegraphics[scale=0.9]{2009_Q23} \\[2ex]


fairly efficient. And finally, putting them into the document

\section*{Topic A}

\subsection*{2006}
\includegraphics[scale=0.9]{2006_Q7} \\[2ex]
\includegraphics[scale=0.9]{2006_Q24} \\[2ex]

\subsection*{2007}
\includegraphics[scale=0.9]{2007_Q11} \\[2ex]
\includegraphics[scale=0.9]{2007_Q24} \\[2ex]

\subsection*{2009}
\includegraphics[scale=0.9]{2009_Q17} \\[2ex]
\includegraphics[scale=0.9]{2009_Q23} \\[2ex]


Question

Is there a more efficient setup (way) to get from

2006    Q7
2006    Q24
2007    Q11
2007    Q24
2009    Q17
2009    Q23


to

\section*{Topic A}

\subsection*{2006}
\includegraphics[scale=0.9]{2006_Q7} \\[2ex]
\includegraphics[scale=0.9]{2006_Q24} \\[2ex]

\subsection*{2007}
\includegraphics[scale=0.9]{2007_Q11} \\[2ex]
\includegraphics[scale=0.9]{2007_Q24} \\[2ex]

\subsection*{2009}
\includegraphics[scale=0.9]{2009_Q17} \\[2ex]
\includegraphics[scale=0.9]{2009_Q23} \\[2ex]


So I just have to manually generate lists of questions by Topic A, Topic B and Topic C ect?

Thanks.

• You probably want a more descriptive title of your question, also, the tag listings is wrong here as the listings package is not related to this question. Note the datatool package can read CSV files, and loop over them, so that can probably be useful for some of this. Other than that, it is sometimes easier to use a different language to generate the latex code, for example python – daleif Aug 7 '18 at 13:23
• you don't want \\[2ex] after the last entry in each paragraph, otherwise tex will complain about underfull box badness 10000 and make very poor output – David Carlisle Aug 7 '18 at 13:23
• @daleif Sory about the tag. I can't really think of any other tags. Will look on datatool. – Chen Stats Yu Aug 7 '18 at 13:25
• You might also look at packages like pgfplotstable and csvsimple, and possibly xstring. – John Kormylo Aug 7 '18 at 13:47
• @ChenStatsYu I added a solution with an explicit list – egreg Aug 7 '18 at 14:07

Assuming the data is contained in a file, you can do something like this:

\begin{filecontents*}{\jobname.lst}
2006    Q7
2006    Q24
2007    Q11
2007    Q24
2009    Q17
2009    Q23
\end{filecontents*}

\documentclass{article}
\usepackage{xparse}
\usepackage[draft]{graphicx}

\ExplSyntaxOn

\NewDocumentCommand{\makereport}{m}
{% #1 = filename
\chenstatsyu_makereport:n { #1 }
}

\ior_new:N \g_chenstatsyu_makereport_stream
\str_new:N \l__chenstatsyu_makereport_year_str

\cs_new_protected:Nn \chenstatsyu_makereport:n
{
\str_clear:N \l__chenstatsyu_makereport_year_str
\ior_open:Nn \g_chenstatsyu_makereport_stream { #1 }
\ior_map_inline:Nn \g_chenstatsyu_makereport_stream
{
\__chenstatsyu_makereport_entry:n { ##1 }
}
\ior_close:N \g_chenstatsyu_makereport_stream
}

\cs_new_protected:Nn \__chenstatsyu_makereport_entry:n
{
\__chenstatsyu_makereport_entry_aux:w #1 \q_stop
}

\cs_new_protected:Npn \__chenstatsyu_makereport_entry_aux:w #1 ~ #2 ~ \q_stop
{
\str_if_eq:VnTF \l__chenstatsyu_makereport_year_str { #1 }
{
\\[2ex]
}
{
\str_set:Nn \l__chenstatsyu_makereport_year_str { #1 }
\subsection*{#1}
}
\includegraphics[height=2cm]{#1_#2} % fix the option
}

\ExplSyntaxOff

\begin{document}

\section*{Topic A}

\makereport{\jobname.lst}

\end{document}


I used draft in order to show the file names (the graphic files are copies of example-image.pdf). Fix the option to \includegraphics to suit you (I don't recommend using scale, though).

If the data is given in the TeX file, it's best to use an explicit line terminator, which should be easy to get with Excel:

\documentclass{article}
\usepackage{xparse}
\usepackage[draft]{graphicx}

\ExplSyntaxOn

\NewDocumentCommand{\makereport}{m}
{% #1 = lines
\chenstatsyu_makereport:n { #1 }
}

\clist_new:N \l__chenstatsyu_makereport_data_clist
\str_new:N \l__chenstatsyu_makereport_year_str

\cs_new_protected:Nn \chenstatsyu_makereport:n
{
\str_clear:N \l__chenstatsyu_makereport_year_str
\clist_set:Nn \l__chenstatsyu_makereport_data_clist { #1 }
\clist_map_function:NN \l__chenstatsyu_makereport_data_clist \__chenstatsyu_makereport_entry:n
}

\cs_new_protected:Nn \__chenstatsyu_makereport_entry:n
{
\__chenstatsyu_makereport_entry_aux:w #1 \q_stop
}

\cs_new_protected:Npn \__chenstatsyu_makereport_entry_aux:w #1 ~ #2 \q_stop
{
\str_if_eq:VnTF \l__chenstatsyu_makereport_year_str { #1 }
{
\\[2ex]
}
{
\str_set:Nn \l__chenstatsyu_makereport_year_str { #1 }
\subsection*{#1}
}
\includegraphics[height=2cm]{#1_#2} % fix the option
}

\ExplSyntaxOff

\begin{document}

\section*{Topic A}

\makereport{
2006    Q7,
2006    Q24,
2007    Q11,
2007    Q24,
2009    Q17,
2009    Q23,
}

\end{document}

• Thanks @egreg. I have decided to go with the \jobname.lst option as this would be easier to maintain when the lists gets longer. Worked perfectly in my big document. – Chen Stats Yu Aug 7 '18 at 14:47
\documentclass{article}

\usepackage[demo]{graphicx}% lose demo in real document

\def\dozzz#1 #2 {%
\def\thissec{#1}%
\ifx\sec\thissec\else
\section*{\thissec}
\let\sec\thissec
\fi
\par\includegraphics[scale=.9]{#1_#2}}

\def\zzzstop{\par}

\def\sec{}

\begin{document}

\setlength\parskip{2ex plus 2ex}
\setlength\parindent{0pt}
\openin\zzz=zzz.txt
\loop
\ifeof\zzz
\else
\ifx\tmp\zzzstop\else
\expandafter\dozzz\tmp
\fi
\repeat
\closein\zzz

\end{document}


where zzz.txt is

2006    Q7
2006    Q24
2007    Q11
2007    Q24
2009    Q17
2009    Q23


The following provides a (La)TeX-based approach.

A (La)TeX-based approach might contribute to reducing the amount of external programs needed.

Whether reducing the amount of external programs needed implies efficiency is another question.

Whether the following approach to the matter can be considered efficient in whatsoever way depends highly on your workflow and on the other tools available and in use anyway.

From time to time I work with data base management systems like MariaDB where data can be exported in various ways, e.g., in csv format. Data in csv format can in LaTeX be processed by means of the datatool package.

Sometimes I use PHP scripts for obtaining data from the database server and creating .tex-files containing the (La)TeX source code for the complete document that is about to be created.

There are scenarios where using such external programs/tools seems more efficient to me than tinkering about with all the possible pitfalls and all kinds of more or less intriguing trickery of macro programming and input parsing in (La)TeX.

But there are many scenarios where using things like database management servers and PHP scripting seems to me like cracking nuts with a sledgehammer. ;-)

You can have (La)TeX allocate a new handle for reading input files (let's call it \MyReadHandle) via \newread\MyReadHandle.

You can have (La)TeX make an input file accessible for reading by having (La)TeX associate that input file to a handle for reading input files.
You can haxe (La)TeX associate to \MyReadHandle an input file whose name is MyInputFile.txt via \openin\MyReadHandle=MyInputFile.txt.
(Some TeX plattforms where file systems can have file names with spaces allow nesting the file name in quotes: \openin\MyReadHandle="MyInputFile.txt".)

You can have (La)TeX define the macro \LineJustRead to expand to the content of the next line of the input file MyInputFile.txt via \read\MyReadHandle to\LineJustRead.

You can have (La)TeX check whether the end of the file associated to \MyReadHandle is reached via \ifeof\MyReadHandle..\else..\fi.

You can have (La)TeX disassociate the file currently associated to \MyReadHandle via \closein\MyReadHandle.

Thus you can have (La)TeX iteratively read your Excel-created-file line-wise to \LineJustRead for parsing the expansion of \LineJustRead via some parsing-macro: \expandafter\MyParsingMacro\LineJustRead.

As (La)TeX usually collapses several consecutive spaces from the input into one space token, you can take lines like

2006    Q7
2006    Q24
2007    Q11
2007    Q24
2009    Q17
2009    Q23


for instances of the pattern

<year><space token><question number>


You can, e.g., attach a catcode-12-return and the pattern becomes:

<year><space token><question number>^^M


, so you can parse with a macro

\def\MyParsingMacro#1 #2^^M{%
#1 is the year.
#2 is the question number.
}



Seems in the scenario provided by you in your question, you won't need routines for removing leading/trailing space tokens from your argument(s).

With other similar scenarios you may need them some day.

Therefore I pasted some routines for space removal with this example although in this specific scenario they are not needed.

In case you don't want them,

• just remove the entire section
EXPANDABLE REMOVAL OF LEADING AND TRAILING SPACES.

• within the section
PARSING FILES WITH LISTS CREATED BY THE EXCEL FILTER
remove the two lines with calls to \UD@TrimAllSurroundSpace
and uncomment the lines below them.

\documentclass{article}
\usepackage[draft]{graphicx}

% verbatim-package is used only for \verbatiminput
% of newly created files.
\usepackage{verbatim}
\makeatletter
% patch \verbatim@processline to also show line-breaks and thus
% also visualize empty lines:
\def\verbatim@processline{%
\the\verbatim@line
{\normalfont\textit{$\mathit{\langle}$linebreak$\mathit{\rangle}$}}%
\par
}
\makeatother

\makeatletter
%%//////////////////////////////////////////////////////////////////////////////
%%
%% Copyright (C) 2007-2018 by  Ulrich W. Diez (ud.usenetcorrespondence@web.de)
%%..............................................................................
%% This work may be distributed and/or modified under the conditions of the
%% LaTeX Project Public Licence (LPPL), either version 1.3 of this license or
%% (at your option) any later version.
%%    http://www.latex-project.org/lppl.txt
%%  and version 1.3 or later is part of all distributions of
%%  LaTeX version 1999/12/01 or later.)
%% The author of this work is Ulrich Diez.
%% This work has the LPPL maintenance status ‘not maintained’.
%% Usage of any/every component of this work is at your own risk.
%% There is no warranty — neither for probably included documentation nor for
%% any other part/component of this work.
%% If something breaks, you usually may keep the pieces.
%%
%% EOF SECTION LICENCE AND COPYRIGHT
%%//////////////////////////////////////////////////////////////////////////////
%%
%%
%%//////////////////////////////////////////////////////////////////////////////
%% SECTION PARAPHERNALIA:
%%
%%    \UD@firstoftwo, \UD@secondoftwo, \UD@Exchange, \UD@CheckWhetherNull,
%%    \UD@CheckWhetherBlank
%%==============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@Exchange[2]{#2#1}%
%%------------------------------------------------------------------------------
%% Check whether argument is empty:
%%..............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%%
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
\UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
\UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%------------------------------------------------------------------------------
%% Check whether argument is blank (empty or only spaces):
%%..............................................................................
%% -- Take advantage of the fact that TeX discards space tokens when
%%    "fetching" _un_delimited arguments: --
%% \UD@CheckWhetherBlank{<Argument which is to be checked>}%
%%                      {<Tokens to be delivered in case that
%%                        argument which is to be checked is blank>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked is not blank}%
\newcommand\UD@CheckWhetherBlank[1]{%
\romannumeral\expandafter\expandafter\expandafter\UD@secondoftwo
\expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo#1{}.}%
}%
%%
%% EOF SECTION PARAPHERNALIA
%%//////////////////////////////////////////////////////////////////////////////
%%
%%
%%//////////////////////////////////////////////////////////////////////////////
%% SECTION EXPANDABLE REMOVAL OF LEADING AND TRAILING SPACES.
%%
%%  - REQUIRES SECTION PARAPHERNALIA.
%%
%%   The obscure case of removing several leading/trailing spaces was taken
%%   into consideration.
%%
%%   Removal of spaces was implemented in a way where no brace-stripping from
%%   the arguments takes place.
%%   Explicit-catcode-1/2-character-token-pairs remain untouched.
%%
%%   Spaces interspersing the argument or hidden within braces will be left in
%%   place.
%%
%%   The arguments themselves do not get expanded.
%%
%%   (For some obscure reason I don't remember any more I needed this in the
%%    past.)
%%
%%==============================================================================
%% Check whether brace-balanced argument starts with a space-token
%%..............................................................................
%% \UD@CheckWhetherLeadingSpace{<Argument which is to be checked>}%
%%                             {<Tokens to be delivered in case <argument
%%                               which is to be checked>'s 1st token is a
%%                               space-token>}%
%%                             {<Tokens to be delivered in case <argument
%%                               which is to be checked>'s 1st token is not
%%                               a space-token>}%
\romannumeral0\UD@CheckWhetherNull{#1}%
{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
}%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@secondoftwo#1{}}%
{\UD@Exchange{\UD@firstoftwo}}{\UD@Exchange{\UD@secondoftwo}}%
{\UD@Exchange{ }{\expandafter\expandafter\expandafter\expandafter
\expandafter\expandafter\expandafter}\expandafter\expandafter
\expandafter}\expandafter\UD@secondoftwo\expandafter{\string}%
}%
%%==============================================================================
%%..............................................................................
%%   expandably removes all leading spaces from  <argument> in case at least
%%   one leading space is present.
%%   Then
%%   is performed.
%%==============================================================================
}%
{%
\expandafter{\UD@removespace#1}{#2}%
}%
{ #2{#1}}%
}%
\newcommand\UD@removespace{}\UD@firstoftwo{\def\UD@removespace}{} {}%
%%==============================================================================
%% \UD@TrimAllTrailSpace{<action>}{<argument>}
%%..............................................................................
%%   expandably removes all trailing spaces from  <argument> in case at least
%%   one trailing space is present.
%%   Then
%%     <action>{<argument without trailing spaces>}
%%   is performed.
%%==============================================================================
\newcommand\UD@TrimAllTrailSpace[2]{%
\romannumeral0\UD@TrimTrailSpaceLoop{#2}{#1}%
}%
%%------------------------------------------------------------------------------
%% \UD@TrimTrailSpaceLoop{<list of space-delimited arguments>}{<action>}
%%..............................................................................
%%   both extracts the first space-delimited argument from the <list of space-
%%   delimited arguments> as {<current argument with one trailing space
%%   removed>} and removes it from the <list of space-delimited arguments> for
%%   obtaining the <remaining list of space delimited arguments> and passes
%%   these two things and an empty list of <arguments preceding the current
%%   argument gathered so far> and the <action> to perform at the end of the
%%   iteration to \UD@CheckWhetherLastSpaceDelimitedItem.
%%
%%   \UD@CheckWhetherLastSpaceDelimitedItem in turn does choose the next
%%   action.
\newcommand\UD@TrimTrailSpaceLoop[2]{%
\UD@ObtainFirstSpaceDelimitedTokenSetLoop{.#1 \UD@SeLDom}{%
\expandafter\UD@CheckWhetherLastSpaceDelimitedItem
\expandafter{\UD@RemoveTokensTillNextSpace.#1 }%
}{}{#2}%
}%
%%------------------------------------------------------------------------------
%% Macros for \UD@ObtainFirstSpaceDelimitedTokenSetLoop.
%%
\newcommand*\UD@RemoveTokensTillNextSpace{}%
\long\def\UD@RemoveTokensTillNextSpace#1 {}%
\newcommand*\UD@BraceStripRemoveNextSpace{}%
\long\def\UD@BraceStripRemoveNextSpace#1 {#1}%
\newcommand*\UD@GetFirstSpaceDelimitedTokenSet{}%
\long\def\UD@GetFirstSpaceDelimitedTokenSet#1 #2\UD@SeLDom{#1 }%
\newcommand\UD@gobbledot{}%
\def\UD@gobbledot.{}%
%%------------------------------------------------------------------------------
%% \UD@ObtainFirstSpaceDelimitedTokenSetLoop%
%%     {<list of space delimited arguments>}%
%%     {<action>}%
%%
%% -> <action>{<first element of list of space delimited arguments>}%
%%...............................................................................
%% \UD@ObtainFirstSpaceDelimitedTokenSetLoop does--without unwanted brace-re-
%% moval--append the first space delimited argument from a
%% <list of space delimited arguments> as brace-delimited argument behind
%% a set of tokens given as <action>.
\newcommand\UD@ObtainFirstSpaceDelimitedTokenSetLoop[1]{%
\expandafter\UD@CheckWhetherNull
\expandafter{\UD@RemoveTokensTillNextSpace#1}{%
\expandafter\expandafter\expandafter\UD@Exchange
\expandafter\expandafter\expandafter{%
\expandafter\expandafter\expandafter{%
\expandafter\UD@gobbledot\UD@BraceStripRemoveNextSpace#1}}%
}{%
\expandafter\UD@ObtainFirstSpaceDelimitedTokenSetLoop
\expandafter{\UD@GetFirstSpaceDelimitedTokenSet#1}%
}%
}%
%%------------------------------------------------------------------------------
%% \UD@CheckWhetherLastSpaceDelimitedItem
%%    {<remaining list of space delimited arguments>}%
%%    {<current argument with one trailing space removed>}%
%%    {<arguments preceding the current argument gathered
%%      so far>}%
%%    {<action>}%
%%..............................................................................
%% Case 1: <remaining list of space delimited arguments> is
%%         empty.
%%         We are done: Thus:
%%         <space>% for terminating \romannumeral-expansion, and
%%         <action>{<arguments preceding the current argument gathered so
%%                   far><current argument with one trailing space removed>}
%% Case 2: <remaining list of space delimited arguments> consists of a single
%%         space.
%%         A trailing space was removed. There may be more. Thus:
%%         \UD@TrimTrailSpaceLoop{%
%%           <arguments preceding the current argument gathered so
%%           far><current argument with one trailing space removed>%
%%         }{<action>}%
%% Neither case 1 nor case 2:
%%         The <current argument with one trailing space  removed> is not the
%%         last argument of the list, thus:
%%         For the next iteration
%%         - attach it and a trailing space to the <arguments preceding the
%%           current argument gathered so far>,
%%         - get the first space delimited argument of the <remaining list of
%%           space delimited arguments> as  <current argument with one trailing
%%           space removed>
%%         - remove that first space delimited argument from the <remaining list
%%           of space delimited arguments>
\newcommand\UD@CheckWhetherLastSpaceDelimitedItem[4]{%
\UD@CheckWhetherNull{#1}{ #4{#3#2}}{%
\expandafter\UD@CheckWhetherNull
\expandafter{\UD@removespace#1}{\UD@firstoftwo}{\UD@secondoftwo}%
}{\UD@secondoftwo}%
{\UD@TrimTrailSpaceLoop{#3#2}{#4}}%
{%
\UD@ObtainFirstSpaceDelimitedTokenSetLoop{.#1\UD@SeLDom}{%
\expandafter\UD@CheckWhetherLastSpaceDelimitedItem
\expandafter{\UD@RemoveTokensTillNextSpace.#1}%
}{#3#2 }{#4}%
}%
}%
}%
%%==============================================================================
%% \UD@TrimAllSurroundSpace{<action>}{<argument>}
%%..............................................................................
%%   expandably removes all leading and trailing spaces from  <argument> in
%%   case at least one leading space is present.
%%   Then
%%     <action>{<argument without leading and trailing spaces>}
%%   is performed.
%%==============================================================================
\newcommand\UD@TrimAllSurroundSpace[2]{%
}%
%%
%% EOF SECTION EXPANDABLE REMOVAL OF LEADING AND TRAILING SPACES.
%%//////////////////////////////////////////////////////////////////////////////
%%
%%
%%//////////////////////////////////////////////////////////////////////////////
%% SECTION PARSING FILES WITH LISTS CREATED BY THE EXCEL FILTER
%%
%%  - REQUIRES MACRO \UD@TrimAllSurroundSpace FROM
%%    SECTION EXPANDABLE REMOVAL OF LEADING AND TRAILING SPACES.
%%
%%  - REQUIRES SECTION PARAPHERNALIA.
%%    (Even when removing the calls to \UD@TrimAllSurroundSpace.)
%%
%%==============================================================================
%% \CreateSectioningFileFromExcelList{%
%%   <phrase before sectioning titles>
%% }{%
%%   <phrase behind sectioning titles>
%% }{%
%%   <phrase before the name of the pdf-file>
%% }{%
%%   <phrase bhind the name of the pdf-file>
%% }{%
%%   <name of file with sectionings that is to be created>
%% }{%
%%   <name of existing file that comes from the excel-filter>
%% }%
%%..............................................................................
%%
\newcommand\UD@LineFromFile{}
\newcommand\UD@YearInPreviousLine{}
\newcommand\UD@YearInThisLine{}
\newcommand\UD@ParseLine{}%
\newwrite\UD@SectioningFile
%%
\begingroup
\endlinechar=-1\relax
\catcode\^^M=12\relax
\UD@secondoftwo{}{%
\endgroup
\newcommand\CreateSectioningFileFromExcelList[6]{%
\begingroup
\renewcommand\UD@LineFromFile{}%
\renewcommand\UD@YearInPreviousLine{}%
\let\do=\@makeother
\dospecials
\catcode\ =10 %
\catcode\^^M=10 %
\openin\UD@TextFileByExcelFilter=#6 %
\ifeof\UD@TextFileByExcelFilter
\expandafter\UD@firstoftwo
\else
\expandafter\UD@secondoftwo
\fi
{%
\@latex@warning@no@line{No file #6.}%
}{%
\IfFileExists{#5}{%
\@latex@warning@no@line{%
File #5' already exists on the system.\MessageBreak
Not generating it from this source%
}%
}{%
\immediate\openout\UD@SectioningFile=#5 %
\loop
\expandafter\UD@CheckWhetherBlank\expandafter{\UD@LineFromFile}{}{%
\expandafter\UD@Exchange
\expandafter{\UD@LineFromFile^^M}{\UD@ParseLine{#1}{#2}{#3}{#4}}%
}%
\repeat
\immediate\closeout\UD@SectioningFile
}%
}%
\closein\UD@TextFileByExcelFilter
\endgroup
}%
%%
%%
\long\def\UD@ParseLine#1#2#3#4#5 #6^^M{%
\UD@TrimAllSurroundSpace{\def\UD@YearInThisLine}%
%\def\UD@YearInThisLine
{#5}%
\ifx\UD@YearInThisLine\UD@YearInPreviousLine
\expandafter\UD@firstoftwo
\else
\expandafter\UD@secondoftwo
\fi
{}{%
\immediate\write\UD@SectioningFile{%
#1\UD@YearInThisLine#2%
}%
}%
\immediate\write\UD@SectioningFile{%
#3%
\UD@YearInThisLine
\UD@CheckWhetherNull{#6}{}{%
\string_%
\UD@TrimAllSurroundSpace{\UD@secondoftwo{}}{#6}%
%#6%
}%
#4%
}%
\let\UD@YearInPreviousLine=\UD@YearInThisLine
}%
}%
\relax
%%
%% EOF SECTION PARSING FILES WITH LISTS CREATED BY THE EXCEL FILTER
%%//////////////////////////////////////////////////////////////////////////////
\makeatother

\edef\endgroupchar{\string}}%
\edef\begingroupchar{\string{}%

\begin{filecontents*}{FromExcel.txt}
2006
2006    Q7
2006    Q24
2007
2007    Q11
2007    Q24
2009    Q17
2009    Q23
\end{filecontents*}

\begin{document}

This is the content of FromExcel.txt

\verbatiminput*{FromExcel.txt}

\CreateSectioningFileFromExcelList{^^J\string\subsection\string*\begingroupchar}%
{\endgroupchar}%
{\string\includegraphics[scale=0.9]\begingroupchar}%
{\endgroupchar\space\string\\[2ex]}%
{MyPictureList.tex}%
{FromExcel.txt}

This is the content of MyPictureList.tex

\verbatiminput*{MyPictureList.tex}

%\input{MyPictureList.tex}

\end{document}