columnify.h
Go to the documentation of this file.
1 /*
2  -------------------------------------------------------------------
3 
4  Copyright (C) 2006-2020, Andrew W. Steiner
5 
6  This file is part of O2scl.
7 
8  O2scl is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 3 of the License, or
11  (at your option) any later version.
12 
13  O2scl is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with O2scl. If not, see <http://www.gnu.org/licenses/>.
20 
21  -------------------------------------------------------------------
22 */
23 #ifndef O2SCL_COLUMNIFY_H
24 #define O2SCL_COLUMNIFY_H
25 
26 /** \file columnify.h
27  \brief Class which formats strings into columns
28 */
29 
30 #include <iostream>
31 #include <string>
32 #include <vector>
33 
34 #include <boost/numeric/ublas/vector.hpp>
35 #include <boost/numeric/ublas/matrix.hpp>
36 
37 #include <o2scl/misc.h>
38 #include <o2scl/string_conv.h>
39 
40 #ifndef DOXYGEN_NO_O2NS
41 namespace o2scl {
42 #endif
43 
44  /** \brief Create nicely formatted columns from a table of strings
45 
46  This is a brute-force approach of order \f$ \mathrm{ncols}
47  \times \mathrm{nrows} \f$. The column widths and spacings of are
48  computed by exhaustively examining all strings in every column.
49 
50  \future Move the screenify() functionality from misc.h into
51  this class?
52  \future It might be better to allow the string table
53  to be specified with iterators.
54  \future Consider a function which takes a \ref o2scl::table
55  object as input?
56  */
57  class columnify {
58 
59  public:
60 
61  columnify() {
62  }
63 
64  /// Align the left-hand sides
65  static const int align_left=1;
66  /// Align the right-hand sides
67  static const int align_right=2;
68  /// Center, slightly to the left if spacing is uneven
69  static const int align_lmid=3;
70  /// Center, slightly to the right if spacing is uneven
71  static const int align_rmid=4;
72  /// Align with decimal points
73  static const int align_dp=5;
74  /** \brief Align negative numbers to the left and use a space for
75  positive numbers
76  */
77  static const int align_lnum=6;
78 
79  /** \brief Take \c table and create a new object \c ctable with
80  appropriately formatted columns
81 
82  The table of strings should be stored in \c table in
83  "column-major" order (<tt>table[ncols][nrows]</tt>), so that
84  \c table has the interpretation of a set of columns to be
85  aligned. Before calling align(), \c ctable should be allocated
86  so that at least the first \c nrows entries can be assigned,
87  and \c align_spec should contain \c ncols entries specifying
88  the style of alignment for each column.
89 
90  The first argument can be any type which is accessible
91  using two applications of <tt>operator[]</tt>, such
92  as <tt>string **</tt>, <tt>vector<string>[]</tt>, or
93  <tt>vector<vector<string> > </tt>
94  */
95  template<class mat_string_t, class vec_string_t, class vec_int_t>
96  int align(const mat_string_t &table, size_t ncols, size_t nrows,
97  vec_string_t &ctable, vec_int_t &align_spec) {
98 
99  // Make space for the size information
102  for(size_t i=0;i<ncols;i++) {
103  csizes[i]=0;
104  csizes2[i]=0;
105  }
106 
107  // Compute the sizes of all the entries in all of the columns so
108  // we know how many spaces to add
109  for(size_t i=0;i<ncols;i++) {
110  for(size_t j=0;j<nrows;j++) {
111 
112  // If we're aligning with decimal points, we need to compute
113  // the maximum width to the left and the right of the
114  // decimal point separately
115 
116  if (align_spec[i]==align_dp) {
117  size_t loc=table[i][j].find('.');
118  std::string left, right;
119  if (loc!=std::string::npos) {
120  left=table[i][j].substr(0,loc+1);
121  right=table[i][j].substr(loc+1,
122  table[i][j].length()-loc-1);
123  } else {
124  left=table[i][j]+' ';
125  right="";
126  }
127  if (left.length()>csizes[i]) csizes[i]=left.length();
128  if (right.length()>csizes2[i]) csizes2[i]=right.length();
129 
130  } else {
131 
132  // Otherwise just find the maximum width of each column
133  if (table[i][j].length()>csizes[i]) csizes[i]=table[i][j].length();
134 
135  }
136 
137  }
138  }
139 
140  // Go through row by row, adding enough spaces to make one string
141  // per row
142  for(size_t j=0;j<nrows;j++) {
143 
144  std::string tmp="";
145 
146  for(size_t i=0;i<ncols;i++) {
147 
148  // Handle each alignment case separately
149  if (align_spec[i]==align_right) {
150 
151  for(size_t k=table[i][j].length();k<csizes[i];k++) {
152  tmp+=' ';
153  }
154  tmp+=table[i][j];
155  if (i!=ncols-1) tmp+=' ';
156 
157  } else if (align_spec[i]==align_left) {
158 
159  tmp+=table[i][j];
160  for(size_t k=table[i][j].length();k<csizes[i];k++) {
161  tmp+=' ';
162  }
163  if (i!=ncols-1) tmp+=' ';
164 
165  } else if (align_spec[i]==align_lmid) {
166 
167  size_t le=(csizes[i]-table[i][j].length())/2;
168  size_t ri=csizes[i]-table[i][j].length()-le;
169  for(size_t k=0;k<le;k++) tmp+=' ';
170  tmp+=table[i][j];
171  for(size_t k=0;k<ri;k++) tmp+=' ';
172  if (i!=ncols-1) tmp+=' ';
173 
174  } else if (align_spec[i]==align_rmid) {
175 
176  size_t ri=(csizes[i]-table[i][j].length())/2;
177  size_t le=csizes[i]-table[i][j].length()-ri;
178  for(size_t k=0;k<le;k++) tmp+=' ';
179  tmp+=table[i][j];
180  for(size_t k=0;k<ri;k++) tmp+=' ';
181  if (i!=ncols-1) tmp+=' ';
182 
183  } else if (align_spec[i]==align_dp) {
184 
185  size_t loc=table[i][j].find('.');
186  std::string left, right;
187  if (loc!=std::string::npos) {
188  left=table[i][j].substr(0,loc+1);
189  right=table[i][j].substr(loc+1,
190  table[i][j].length()-loc-1);
191  } else {
192  left=table[i][j]+' ';
193  right="";
194  }
195 
196  for(size_t k=left.length();k<csizes[i];k++) tmp+=' ';
197  tmp+=left;
198  tmp+=right;
199  for(size_t k=right.length();k<csizes2[i];k++) tmp+=' ';
200  if (i!=ncols-1) tmp+=' ';
201 
202  } else if (align_spec[i]==align_lnum) {
203 
204  if (table[i][j].length()==csizes[i]) {
205  tmp+=table[i][j];
206  } else {
207  if (table[i][j][0]>='0' && table[i][j][0]<='9') {
208  tmp+=' ';
209  tmp+=table[i][j];
210  for(size_t k=table[i][j].length();k<csizes[i]-1;k++) {
211  tmp+=' ';
212  }
213  } else {
214  tmp+=table[i][j];
215  for(size_t k=table[i][j].length();k<csizes[i];k++) {
216  tmp+=' ';
217  }
218  }
219  }
220  if (i!=ncols-1) tmp+=' ';
221  }
222 
223  // Proceed to the next column
224  }
225 
226  // Add the row to the user-specified array and go to the next row
227  ctable[j]=tmp;
228 
229  }
230 
231  return 0;
232  }
233 
234  };
235 
236  /// \name Matrix output functions from src/base/columnify.h
237  //@{
238  /** \brief A operator for simple matrix output using \c operator()
239 
240  The type \c mat_t can be any matrix type which allows
241  individual element access using <tt>operator()(size_t,size_t)</tt>.
242 
243  This outputs all of the matrix elements using output settings
244  specified by \c os. The alignment performed by \ref columnify
245  using columnify::align_dp, i.e. the numbers are aligned by
246  their decimal points. If the numbers have no decimal points,
247  then the decimal point is assumed to be to the right of the
248  last character in the string representation of the number.
249 
250  This function outputs the matrix assuming the first index is the
251  row index and the second index is the column index. For the
252  opposite convention, use \ref matrix_trans_out().
253  */
254  template<class mat_t> int matrix_out(std::ostream &os, size_t nrows,
255  size_t ncols, const mat_t &A) {
256 
257  columnify co;
258  std::vector<std::vector<std::string> > stab(ncols);
259  std::vector<std::string> ctable(nrows);
260  std::vector<int> alig(ncols);
261 
262  for(size_t j=0;j<ncols;j++) {
263  alig[j]=columnify::align_dp;
264  for(size_t i=0;i<nrows;i++) {
265  stab[j].push_back(dtos(A(i,j),os));
266  }
267  }
268  co.align(stab,ncols,nrows,ctable,alig);
269  for(size_t i=0;i<nrows;i++) {
270  os << ctable[i] << std::endl;
271  }
272 
273  return 0;
274  }
275 
276  /** \brief A operator for simple matrix output using \c operator()
277 
278  The type \c mat_t can be any matrix type which allows
279  individual element access using <tt>operator()(size_t,size_t)</tt>
280  and access to the number of columns and rows using
281  <tt>A.size1()</tt> and <tt>A.size2()</tt>.
282 
283  This outputs all of the matrix elements using output settings
284  specified by \c os. The alignment performed by \ref columnify
285  using columnify::align_dp, i.e. the numbers are aligned by
286  their decimal points. If the numbers have no decimal points,
287  then the decimal point is assumed to be to the right of the
288  last character in the string representation of the number.
289 
290  This function outputs the matrix assuming the first index is the
291  row index and the second index is the column index. For the
292  opposite convention, use \ref matrix_trans_out().
293  */
294  template<class mat_t> int matrix_out(std::ostream &os, const mat_t &A) {
295 
296  size_t nrows=A.size1();
297  size_t ncols=A.size2();
298 
299  columnify co;
300  std::vector<std::vector<std::string> > stab(ncols);
301  std::vector<std::string> ctable(nrows);
302  std::vector<int> alig(ncols);
303 
304  for(size_t j=0;j<ncols;j++) {
305  alig[j]=columnify::align_dp;
306  for(size_t i=0;i<nrows;i++) {
307  stab[j].push_back(dtos(A(i,j),os));
308  }
309  }
310  co.align(stab,ncols,nrows,ctable,alig);
311  for(size_t i=0;i<nrows;i++) {
312  os << ctable[i] << std::endl;
313  }
314 
315  return 0;
316  }
317 
318  /** \brief A operator for simple matrix output using \c operator()
319 
320  The type \c mat_t can be any matrix type which allows
321  individual element access using <tt>operator()(size_t,size_t)</tt>.
322 
323  This outputs all of the matrix elements using output settings
324  specified by \c os. The alignment performed by \ref columnify
325  using columnify::align_dp, i.e. the numbers are aligned by
326  their decimal points. If the numbers have no decimal points,
327  then the decimal point is assumed to be to the right of the
328  last character in the string representation of the number.
329 
330  This function outputs the matrix assuming the first index is the
331  column index and the second index is the row index. For the
332  opposite convention, use \ref matrix_out().
333  */
334  template<class mat_t> int matrix_trans_out(std::ostream &os, size_t nrows,
335  size_t ncols, const mat_t &A) {
336 
337  columnify co;
338  std::vector<std::vector<std::string> > stab(nrows);
339  std::vector<std::string> ctable(ncols);
340  std::vector<int> alig(nrows);
341 
342  for(size_t i=0;i<nrows;i++) {
343  alig[i]=columnify::align_dp;
344  for(size_t j=0;j<ncols;j++) {
345  stab[i].push_back(dtos(A(i,j),os));
346  }
347  }
348  co.align(stab,nrows,ncols,ctable,alig);
349  for(size_t i=0;i<ncols;i++) {
350  os << ctable[i] << std::endl;
351  }
352 
353  return 0;
354  }
355 
356  /** \brief A operator for simple matrix output using \c operator()
357 
358  The type \c mat_t can be any matrix type which allows
359  individual element access using <tt>operator()(size_t,size_t)</tt>
360  and access to the number of columns and rows using
361  <tt>A.size1()</tt> and <tt>A.size2()</tt>.
362 
363  This outputs all of the matrix elements using output settings
364  specified by \c os. The alignment performed by \ref columnify
365  using columnify::align_dp, i.e. the numbers are aligned by
366  their decimal points. If the numbers have no decimal points,
367  then the decimal point is assumed to be to the right of the
368  last character in the string representation of the number.
369 
370  This function outputs the matrix assuming the first index is the
371  column index and the second index is the row index. For the
372  opposite convention, use \ref matrix_out().
373  */
374  template<class mat_t> int matrix_trans_out(std::ostream &os,
375  const mat_t &A) {
376 
377  size_t nrows=A.size1();
378  size_t ncols=A.size2();
379 
380  columnify co;
381  std::vector<std::vector<std::string> > stab(nrows);
382  std::vector<std::string> ctable(ncols);
383  std::vector<int> alig(nrows);
384 
385  for(size_t i=0;i<nrows;i++) {
386  alig[i]=columnify::align_dp;
387  for(size_t j=0;j<ncols;j++) {
388  stab[i].push_back(dtos(A(i,j),os));
389  }
390  }
391  co.align(stab,nrows,ncols,ctable,alig);
392  for(size_t i=0;i<ncols;i++) {
393  os << ctable[i] << std::endl;
394  }
395 
396  return 0;
397  }
398 
399  /** \brief A operator for simple matrix output using \c operator[]
400 
401  The type \c mat_t can be any 2d-array type which allows
402  individual element access using \c [size_t][size_t]
403 
404  This outputs all of the matrix elements using output settings
405  specified by \c os. The alignment performed by \ref columnify
406  using columnify::align_dp, i.e. the numbers are aligned by
407  their decimal points. If the numbers have no decimal points,
408  then the decimal point is assumed to be to the right of the
409  last character in the string representation of the number.
410 
411  This function outputs the matrix assuming the first index is the
412  row index and the second index is the column index. For the
413  opposite convention, use \ref array_2d_trans_out().
414 
415  \future If all of the matrix elements are positive integers
416  and scientific mode is not set, then we can avoid printing
417  the extra spaces.
418  */
419  template<class mat_t> int array_2d_out(std::ostream &os, size_t nrows,
420  size_t ncols, mat_t &A) {
421 
422  columnify co;
423  std::vector<std::string> *stab=new std::vector<std::string>[ncols];
424  std::vector<std::string> ctable(nrows);
425  std::vector<int> alig(ncols);
426 
427  for(size_t j=0;j<ncols;j++) {
428  alig[j]=columnify::align_dp;
429  for(size_t i=0;i<nrows;i++) {
430  stab[j].push_back(dtos(A[i][j],os));
431  }
432  }
433  co.align(stab,ncols,nrows,ctable,alig);
434  for(size_t i=0;i<nrows;i++) {
435  os << ctable[i] << std::endl;
436  }
437 
438  delete[] stab;
439 
440  return 0;
441  }
442 
443  /** \brief A operator for simple matrix output using \c operator[]
444 
445  The type \c mat_t can be any 2d-array type which allows
446  individual element access using \c [size_t][size_t]
447 
448  This outputs all of the matrix elements using output settings
449  specified by \c os. The alignment performed by \ref columnify
450  using columnify::align_dp, i.e. the numbers are aligned by
451  their decimal points. If the numbers have no decimal points,
452  then the decimal point is assumed to be to the right of the
453  last character in the string representation of the number.
454 
455  \future If all of the matrix elements are positive integers
456  and scientific mode is not set, then we can avoid printing
457  the extra spaces.
458 
459  This function outputs the matrix assuming the first index is the
460  column index and the second index is the row index. For the
461  opposite convention, use \ref array_2d_out().
462  */
463  template<class mat_t> int array_2d_trans_out(std::ostream &os, size_t nrows,
464  size_t ncols, mat_t &A) {
465 
466  columnify co;
467  std::vector<std::string> *stab=new std::vector<std::string>[nrows];
468  std::vector<std::string> ctable(ncols);
469  std::vector<int> alig(nrows);
470 
471  for(size_t i=0;i<nrows;i++) {
472  alig[i]=columnify::align_dp;
473  for(size_t j=0;j<ncols;j++) {
474  stab[i].push_back(dtos(A[i][j],os));
475  }
476  }
477  co.align(stab,nrows,ncols,ctable,alig);
478  for(size_t i=0;i<ncols;i++) {
479  os << ctable[i] << std::endl;
480  }
481 
482  delete[] stab;
483 
484  return 0;
485  }
486  //@}
487 
488 #ifndef DOXYGEN_NO_O2NS
489 }
490 #endif
491 
492 #endif
o2scl::columnify
Create nicely formatted columns from a table of strings.
Definition: columnify.h:57
o2scl::table
Data table table class.
Definition: table.h:49
o2scl::dtos
std::string dtos(const fp_t &x, int prec=6, bool auto_prec=false)
Convert a double to a string.
Definition: string_conv.h:77
o2scl::columnify::align_right
static const int align_right
Align the right-hand sides.
Definition: columnify.h:67
boost::numeric::ublas::vector< size_t >
o2scl::columnify::align_lmid
static const int align_lmid
Center, slightly to the left if spacing is uneven.
Definition: columnify.h:69
o2scl::array_2d_out
int array_2d_out(std::ostream &os, size_t nrows, size_t ncols, mat_t &A)
A operator for simple matrix output using operator[].
Definition: columnify.h:419
o2scl::matrix_out
int matrix_out(std::ostream &os, size_t nrows, size_t ncols, const mat_t &A)
A operator for simple matrix output using operator()
Definition: columnify.h:254
o2scl::columnify::align_lnum
static const int align_lnum
Align negative numbers to the left and use a space for positive numbers.
Definition: columnify.h:77
o2scl
The main O<span style='position: relative; top: 0.3em; font-size: 0.8em'>2</span>scl O$_2$scl names...
Definition: anneal.h:42
o2scl::columnify::align_dp
static const int align_dp
Align with decimal points.
Definition: columnify.h:73
o2scl::columnify::align
int align(const mat_string_t &table, size_t ncols, size_t nrows, vec_string_t &ctable, vec_int_t &align_spec)
Take table and create a new object ctable with appropriately formatted columns.
Definition: columnify.h:96
o2scl::array_2d_trans_out
int array_2d_trans_out(std::ostream &os, size_t nrows, size_t ncols, mat_t &A)
A operator for simple matrix output using operator[].
Definition: columnify.h:463
o2scl::columnify::align_left
static const int align_left
Align the left-hand sides.
Definition: columnify.h:65
o2scl::matrix_trans_out
int matrix_trans_out(std::ostream &os, size_t nrows, size_t ncols, const mat_t &A)
A operator for simple matrix output using operator()
Definition: columnify.h:334
o2scl::columnify::align_rmid
static const int align_rmid
Center, slightly to the right if spacing is uneven.
Definition: columnify.h:71

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).