4

I'm trying to put the number of rows of a csv file into a latex document, without actually putting the table into the last document.

I've tried the tag package, and putting the table in another latex document with the "\thenumberofrows" between tags. However, when I use "\ExecuteMetaData[file.tex]{tag}" in the real document, it doesn't work and just gives 0 because the table is not in the real document.

So, I need to have an "invisible" table in my real document, that I can take the number of rows from that one. I tried putting the table writing white, but this takes up space in the document. If I can put text over this white table, then it wouldn't be a problem.

If anyone can help me with putting an 'invisible table' on latex, that would be very much appreciated!

Val

  • Can you post a sample compilable document that shows what you're trying to do. What do you mean by an invisible table? Do you just need to know how many rows an external CSV file has, and then use that number in the LaTeX document? – Alan Munn May 26 '17 at 21:53
  • If you only want the number of rows of a particular CSV file, that's easy to do with csvsimple. – Alan Munn May 26 '17 at 22:13
4

You can count lines in a file by opening and reading it:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\countlines}{om}
 {
  \int_zero:N \l_tmpa_int
  \ior_open:Nn \valerie_countlines_stream { #2 }
  \ior_str_map_inline:Nn \valerie_countlines_stream
   {
    \int_incr:N \l_tmpa_int
   }
  \ior_close:N \valerie_countlines_stream
  \IfNoValueTF{#1}
   {
    \int_eval:n { \l_tmpa_int }
   }
   {
    \tl_set:Nx #1 { \int_eval:n { \l_tmpa_int } }
   }
 }
\ior_new:N \valerie_countlines_stream
\ExplSyntaxOff

\begin{document}

This very document has \countlines{\jobname.tex} lines.

\countlines[\thisfile]{\jobname.tex}

The number can be stored in \verb|\thisfile|: \thisfile

\end{document}

enter image description here

With datatool:

\begin{filecontents*}{\jobname.csv}
a,b,c,d
1,2,3,4
x,y,z,t
\end{filecontents*}

\documentclass{article}

\usepackage{datatool}

\DTLloaddb{test}{\jobname.csv}

\begin{document}

\DTLrowcount{test}

\end{document}

This will print 2, because the first line is, by default, considered headers. If you load the file with

\DTLloaddb[noheader]{test}{\jobname.csv}

you'd get 3.

You can also do

\edef\thisfile{\DTLrowcount{test}}

and the macro \thisfile will expand to the same number.

  • 1
    Couldn't wait, I see. – Alan Munn May 26 '17 at 23:08
6

You can easily count lines with csvsimple. You just need to use a \csvreader command that does nothing with the row contents:

\csvreader{<file>}{}{}

If you want to include first line of the file in the count, you can add no head to the \csvreader command.

\csvreader[no head]{<file>}{}{}

The number of rows processed is stored in the counter csvrow which can be printed with \thecsvrow. Here's a complete example.

\documentclass{article}
\usepackage{filecontents}
\begin{filecontents*}{\jobname.csv}
ColA,ColB,ColC
A1,B1,C1
A2,B2,C2
A3,B3,C3
A4,B4,C4
A5,B5,C5
A6,B6,C6
A7,B7,C7
\end{filecontents*}
\begin{filecontents*}{\jobname B.csv}
ColA,ColB,ColC
A1,B1,C1
A2,B2,C2
A3,B3,C3
\end{filecontents*}
\usepackage{csvsimple}

\begin{document}
\csvautotabular{\jobname.csv}

\csvreader{\jobname.csv}{}{}

This CSV file has \thecsvrow\ rows.
\bigskip

\csvautotabular{\jobname B.csv}

\csvreader[no head]{\jobname B.csv}{}{}

This CSV file has \thecsvrow\ rows (header included).

\end{document}

output of code

1

The readarray package can import and count data from a file. Here I read it as a record array (ignore any columns). The row count can sometimes be 1 larger than you wish, if the file ends with a blank line. So I did a quick \if test to screen out that case.

The package can also read in 2-D and 3-D array data, and store it in indexed structures.

\begin{filecontents*}{\jobname.csv}
a,b,c,d
1,2,3,4
x,y,z,t
\end{filecontents*}
\documentclass{article}
\usepackage{readarray}
\begin{document}
\readrecordarray{\jobname.csv}\mydata
Records in file: 
\if\relax\mydata[\mydataROWS]\relax\the\numexpr\mydataROWS-1\else\mydataROWS\fi
\end{document}

enter image description here

To give a fuller example of its array-reading capabilities:

\begin{filecontents*}{\jobname.csv}
a,b,cCc,d
1,2,3,4
x,y,z3po ,t
\end{filecontents*}
\documentclass{article}
\usepackage{readarray}
\begin{document}
\obeylines
\readarraysepchar{,}
\readdef{\jobname.csv}\mydef
\readarray*\mydef\mydata[-,\ncols]
Rows, columns read: \mydataROWS, \mydataCOLS\par
making a total of \mydataCELLS{} cells.\par
cell[3,2] is \mydata[3,2]\par
Here is the arraydump of mydata: \arraydump\mydata
Bounds checking\par
no error checking on cell [5,1]: \mydata[5,1]\par
\checkbounds
checkbounds error checking on cell [5,1]: \mydata[5,1]\par
\hypercheckbounds
hyper-checkbounds error checking on cell [5,1]: \mydata[5,1]\par
Log file extract:
\begin{verbatim}
readarray: bounds checking ON
readarray Warning: \mydata[5,1]  out of bounds.
readarray: bounds hyperchecking ON
readarray Warning: \mydata[5,1]  out of bounds:
ROW=5 exceeds bounds(=3) for mydata.
\end{verbatim}
\end{document}

enter image description here

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.