# Read line by line the contents of \NewEnviron including “\\”

I am trying to create a new environment and use it as a customized array (with many changes in the code given). So I need to read the \BODY of the \NewEnviron and read it line by line. I don't care if I have to finish the lines with \\ or with empty line or whatever. But I have to read them one by one and I don't know how many lines there are before using the environment.

I tried this:

\documentclass{article}
\usepackage{environ}
\usepackage{xstring}

\makeatletter
\long\def\findLength#1{\StrLen{#1}[\temp] The length of #1'' is \temp\\}
\NewEnviron{Graph}{\findLength{\BODY}}{}
\makeatother

\begin{document}

\begin{Graph}
test line 1

test line 2
\end{Graph}

\end{document}


But uses all the \BODY and not line by line. Also If I add a linebreak the #1 of \StrLen is no more a string (contains linebreak and gives errors).

I have finally manage to take the first line in my new environment using the code of @Bruno Le Floch from here but I don't really understand that code and I don't know what to read to understand it and change it for taking all the arguments. Also I can not yet add \ in the end of the rows to show where the line of the array ends... Here is what I have now:

\documentclass{article}
\usepackage{environ}% defines NewEnviron
\usepackage{xstring}

\makeatletter
\newcommand*{\newlinecommand}[2]{%
\newcommand*{#1}{%
\begingroup%
\escapechar=\\%
\catcode\endlinechar=\active%
\csname\string#1\endcsname%
}%
\begingroup%
\escapechar=\\%
\lccode\~=\endlinechar%
\lowercase{%
\expandafter\endgroup
\expandafter\def\csname\string#1\endcsname##1~%
}{\endgroup#2\par\space}%
}
\makeatother

\makeatletter
\newlinecommand{\findLengthOfRow}{\StrLen{#1}[\temp] The length of #1'' is \temp}
\makeatother

\makeatletter
\long\def\findLength#1{\findLengthOfRow{#1}}
\newenvironment{Graph}{\findLength}{}
\makeatother

\begin{document}

\begin{Graph}
test line 1
test line 2
test line 3
\end{Graph}

\end{document}


Any help will be appreciated. The result I want is to take as arguments the rows in the environment. (I don't now how many rows will have the array. So don't give specific number of arguments in the newenvironment).

This uses the powerful listofitems package to parse the \BODY, using \\ separators.

\documentclass[12pt]{article}
\usepackage{listofitems,environ}
\NewEnviron{linebyline}{%
\setsepchar{\\}%
\foreachitem\x\in\mylines{Line \xcnt: \x\par}%
The total number of lines is \textbf{\listlen\mylines[]}.
}
\begin{document}
\begin{linebyline}
This is a test\\
of whether\\
I can identify line by line.
\end{linebyline}
\end{document}


And this shows how to further sub-parse each line, word by word, using a space as the 2nd tier separator:

\documentclass[12pt]{article}
\usepackage{listofitems,environ}
\NewEnviron{linebyline}{%
\setsepchar{\\/ }%
\foreachitem\x\in\mylines{Line \xcnt: \x{} (has \listlen\mylines[\xcnt] words,
first/last: \mylines[\xcnt,1]/\mylines[\xcnt,-1]'')\par}%
The total number of lines is \textbf{\listlen\mylines[]}.
}
\begin{document}
\begin{linebyline}
This is a test\\
of whether\\
I can identify line by line.
\end{linebyline}
\end{document}


• Thank you very much @Steven B. Segletes... Does readarray includes listofitems? I see I can run both of the codes... so it is not a typo... Do you include listofitems in readarray? (I suppose you do)... You have done very nice work there! Thanks again. – koleygr Jun 30 '17 at 11:21
• @koleygr Thanks for pointing that out. Yes, readarray loads listofitems, but I do not need readarray in the 2nd example...I had been considering a feature that would have required readarray, but as it turns out, I did not use it. So I re-edited my answer to reflect the package listofitems, since that is all you need for these cases. – Steven B. Segletes Jun 30 '17 at 14:10
• Thanks for your effort to do this... I will probably choose your answer because it is closer to what I wanted from the beginning but now I am working on @egreg's work because I had started to work with it and he made a good job too (even if I don't prefer LaTeX3 for the moment)... I suppose I can add a \global\expandafter\let... etc in the place you are printing to be more comfortable in using the results... Thanks again! – koleygr Jun 30 '17 at 14:20
• @koleygr If you use \greadlist* instead of \readlist*, the result is available globally. There is no need for you to provide additional \lets. To access line 2, use \mylines[2], to access the 3rd word of line 1 [Using my 2nd MWE] , for example, use \mylines[1,3]. To get the actual tokens from that line of \BODY, you would have to expand twice the value of \mylines[]. – Steven B. Segletes Jun 30 '17 at 14:23
• Thank you.. I will try soon. (very good addition the greadlist*) Bravo again! – koleygr Jun 30 '17 at 14:33

If you don't care whether lines are ended by \\ (which is safer than monkeying with \endlinechar), it's really simple with expl3.

\documentclass{article}
\usepackage{xparse,environ}

\ExplSyntaxOn
\NewEnviron{Graph}
{
% split the environment's contents into items at the \\ separator
\seq_set_split:NnV \l_koleygr_graph_lines_seq { \\ } \BODY
\begin{enumerate}
% map over the sequence, passing each item to the internal function
\seq_map_function:NN \l_koleygr_graph_lines_seq \koleygr_graph_doline:n
\end{enumerate}
}

\cs_new_protected:Nn \koleygr_graph_doline:n
{
\tl_if_empty:nF { #1 }
{
\item #1
}
}
\ExplSyntaxOff

\begin{document}

Something at the top
\begin{Graph}
Line 1\\
Line 2\\
Line 3
\end{Graph}
Something in between
\begin{Graph}
Line 1\\
Line 2\\
Line 3\\
\end{Graph}
Something at the bottom

\end{document}


I used a dummy action to be performed on each line, just by way of example. The check for emptiness is shown to be useful in case the last line ends with \\. There are other possibilities: one can simply check whether the last item in the sequence obtained from \BODY` is empty. It all depends on what you want to do with the environment’s contents.

• Thanks @egreg, I will wait for other answers too in LaTeX2e... I discovered expll13 these days (since I signed up here) but I am not ready for this yet... Thanks.. I am sure that your answer will help many people... – koleygr Jun 30 '17 at 8:53