Quick LaTeX tables using TextExpander

When I want to include a numerical table in a LaTeX document I often already have the data collected together in a Numbers spreadsheet with the desired layout. For example, I might want to go from:

to

 

The following TextExpander snippet (gist) lets me simply copy the data from Numbers, including the column headers, to the clipboard, and then insert it into a LaTeX document as a nicely formatted table by typing ;ptable:[1]

#!/usr/local/bin/ruby

class Line

  @@max_length = nil
  @@eol = ' \\\\'

  def initialize( data )
    @contents = data
    @@max_length = [0]*@contents.size if @@max_length.nil? # initialize array if this is the first Line instance
    @contents.each_with_index{ |element, i| @@max_length[i] = [element.length, @@max_length[i]].max } # update column widths
  end

  def to_tex
    @contents.zip( @@max_length ).collect { |entry, length| entry.ljust(length).sub(/ \|$/,'').gsub('&','\\\&') }.join(' & ') + @@eol
  end

  def define_format
     @contents.inject('|'){ |string, entry| /\|/.match(entry) ?  string + 'c|' : string + 'c' } + '|'
  end

end

table_header = <<END
\\begin{table}[htb]
\\begin{center}
\\begin{tabular}{FORMAT} \\hline 
END # FORMAT is replaced by a format string generated by define_format

table_footer = <<END
\\hline
\\end{tabular}
\\caption{\\label{tab:NEW_LABEL}CAPTION}
\\end{center}
\\end{table}
END

contents = "%clipboard".split( /[\n\r]/ ).collect{ |line| Line.new( line.split( /\t/ ) )}

puts table_header.sub( 'FORMAT', contents[0].define_format ) 
puts contents.collect{ |line| line.to_tex }.join("\n")
puts table_footer

Running this snippet with the data shown above produces the following LaTeX code:

\begin{table}[htb]
\begin{center}
\begin{tabular}{|c|c|c|} \hline
A     & B     & C     \\
12.62 & 12.62 & 33.88 \\
3.96  & 4.39  & 4.55  \\
2.00  & 2.30  & 2.56  \\
\hline
\end{tabular}
\caption{\label{tab:NEW_LABEL}CAPTION}
\end{center}
\end{table}

The script assumes centred justification of each column. A limited amount of table formatting can be specified in the Numbers data: any cells in the topmost row can include a pipe character | to indicate that this column should be bounded by a vertical line on the right side, e.g. column 1 | will add a c| format string to the begin{tabular}{FORMAT} code in the LaTeX header via the define_format method.


  1. Inspired by a similar workflow by Dr Drang for copying tables from Numbers to Markdown.  ↩