columnify.h
Go to the documentation of this file.
1 /*
2  -------------------------------------------------------------------
3 
4  Copyright (C) 2006-2017, 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 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, 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, 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, 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, mat_t &A) {
375 
376  size_t nrows=A.size1();
377  size_t ncols=A.size2();
378 
379  columnify co;
380  std::vector<std::vector<std::string> > stab(nrows);
381  std::vector<std::string> ctable(ncols);
382  std::vector<int> alig(nrows);
383 
384  for(size_t i=0;i<nrows;i++) {
385  alig[i]=columnify::align_dp;
386  for(size_t j=0;j<ncols;j++) {
387  stab[i].push_back(dtos(A(i,j),os));
388  }
389  }
390  co.align(stab,nrows,ncols,ctable,alig);
391  for(size_t i=0;i<ncols;i++) {
392  os << ctable[i] << std::endl;
393  }
394 
395  return 0;
396  }
397 
398  /** \brief A operator for simple matrix output using \c operator[]
399 
400  The type \c mat_t can be any 2d-array type which allows
401  individual element access using \c [size_t][size_t]
402 
403  This outputs all of the matrix elements using output settings
404  specified by \c os. The alignment performed by \ref columnify
405  using columnify::align_dp, i.e. the numbers are aligned by
406  their decimal points. If the numbers have no decimal points,
407  then the decimal point is assumed to be to the right of the
408  last character in the string representation of the number.
409 
410  This function outputs the matrix assuming the first index is the
411  row index and the second index is the column index. For the
412  opposite convention, use \ref array_2d_trans_out().
413 
414  \future If all of the matrix elements are positive integers
415  and scientific mode is not set, then we can avoid printing
416  the extra spaces.
417  */
418  template<class mat_t> int array_2d_out(std::ostream &os, size_t nrows,
419  size_t ncols, mat_t &A) {
420 
421  columnify co;
422  std::vector<std::string> *stab=new std::vector<std::string>[ncols];
423  std::vector<std::string> ctable(nrows);
424  std::vector<int> alig(ncols);
425 
426  for(size_t j=0;j<ncols;j++) {
427  alig[j]=columnify::align_dp;
428  for(size_t i=0;i<nrows;i++) {
429  stab[j].push_back(dtos(A[i][j],os));
430  }
431  }
432  co.align(stab,ncols,nrows,ctable,alig);
433  for(size_t i=0;i<nrows;i++) {
434  os << ctable[i] << std::endl;
435  }
436 
437  delete[] stab;
438 
439  return 0;
440  }
441 
442  /** \brief A operator for simple matrix output using \c operator[]
443 
444  The type \c mat_t can be any 2d-array type which allows
445  individual element access using \c [size_t][size_t]
446 
447  This outputs all of the matrix elements using output settings
448  specified by \c os. The alignment performed by \ref columnify
449  using columnify::align_dp, i.e. the numbers are aligned by
450  their decimal points. If the numbers have no decimal points,
451  then the decimal point is assumed to be to the right of the
452  last character in the string representation of the number.
453 
454  \future If all of the matrix elements are positive integers
455  and scientific mode is not set, then we can avoid printing
456  the extra spaces.
457 
458  This function outputs the matrix assuming the first index is the
459  column index and the second index is the row index. For the
460  opposite convention, use \ref array_2d_out().
461  */
462  template<class mat_t> int array_2d_trans_out(std::ostream &os, size_t nrows,
463  size_t ncols, mat_t &A) {
464 
465  columnify co;
466  std::vector<std::string> *stab=new std::vector<std::string>[nrows];
467  std::vector<std::string> ctable(ncols);
468  std::vector<int> alig(nrows);
469 
470  for(size_t i=0;i<nrows;i++) {
471  alig[i]=columnify::align_dp;
472  for(size_t j=0;j<ncols;j++) {
473  stab[i].push_back(dtos(A[i][j],os));
474  }
475  }
476  co.align(stab,nrows,ncols,ctable,alig);
477  for(size_t i=0;i<ncols;i++) {
478  os << ctable[i] << std::endl;
479  }
480 
481  delete[] stab;
482 
483  return 0;
484  }
485  //@}
486 
487 #ifndef DOXYGEN_NO_O2NS
488 }
489 #endif
490 
491 #endif
The main O<span style=&#39;position: relative; top: 0.3em; font-size: 0.8em&#39;>2</span>scl O$_2$scl names...
Definition: anneal.h:42
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
Create nicely formatted columns from a table of strings.
Definition: columnify.h:57
Data table table class.
Definition: table.h:49
static const int align_left
Align the left-hand sides.
Definition: columnify.h:65
int matrix_out(std::ostream &os, size_t nrows, size_t ncols, mat_t &A)
A operator for simple matrix output using operator()
Definition: columnify.h:254
static const int align_lnum
Align negative numbers to the left and use a space for positive numbers.
Definition: columnify.h:77
static const int align_right
Align the right-hand sides.
Definition: columnify.h:67
static const int align_rmid
Center, slightly to the right if spacing is uneven.
Definition: columnify.h:71
int matrix_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:334
std::string dtos(double x, int prec=6, bool auto_prec=false)
Convert a double to a string.
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:462
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:418
static const int align_lmid
Center, slightly to the left if spacing is uneven.
Definition: columnify.h:69
static const int align_dp
Align with decimal points.
Definition: columnify.h:73

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