// CS 509 Advanced Programming II
// Fall 2002
// Programming Assignment 1 Example Solution
#include <iostream>
#include <string>
#include <cassert>
// Some useful typedefs.
typedef std::string ss_row;
typedef ss_row * spreadsheet;
typedef std::string::size_type str_indx;
typedef const char * const cchar_cptr;
// A column c in line l begins at l[c.begin] and ends at l[c.end - 1].
struct column {
str_indx begin, end;
};
typedef const column * const ccol_cptr;
// Deja vu, c++ style.
static void mask_out(ss_row &, const ss_row &);
static bool readline(std::istream &, ss_row &);
static spreadsheet read_spreadsheet(std::istream &, unsigned);
static bool parse_spec(const std::string &, column &, column &);
static void print_section(
std::ostream &, const spreadsheet, ccol_cptr, cchar_cptr);
static bool split(const std::string &, cchar_cptr, ss_row &, ss_row &);
static column *
find_columns(const ss_row & mask, str_indx start = 0, unsigned count = 0) {
// Pick off the column starting at start in mask, storing the column
// information in the count-th element of the array returned. The end of the
// array is marked by the column beginning at string::npos.
column c, * columns;
c.begin = mask.find_first_not_of(" ", start);
if (c.begin == std::string::npos)
columns = new column[count + 1];
else {
c.end = mask.find_first_of(" ", c.begin);
if (c.end == std::string::npos)
c.end = mask.length();
columns = find_columns(mask, c.end, count + 1);
}
columns[count] = c;
return columns;
}
static bool
is_int(const std::string & str) {
// Return true iff str contains an unsigned integer.
return !str.empty() and
(str.find_first_not_of("0123456789") == std::string::npos);
}
int
main(int argc, char * argv[]) {
const spreadsheet ss = read_spreadsheet(std::cin, 0);
ss_row mask;
for (unsigned i = 0; ss[i].length() > 0; i++)
mask_out(mask, ss[i]);
ccol_cptr columns = find_columns(mask);
const char * sep = "";
for (int i = 1; i < argc; i++) {
std::cout << sep;
print_section(std::cout, ss, columns, argv[i]);
sep = "\n";
}
delete [] ss;
delete [] columns;
}
static void
mask_out(ss_row & mask, const ss_row & line) {
// If line[i] is not a space character, store a '*' in mask[i]; if line[i] is
// a space character, mask[i] is unchanged. If line is longer than mask,
// mask is padded with space charaters to the right to make it the same size
// as line.
const int diff = line.length() - mask.length();
if (diff > 0)
mask += ss_row(diff, ' ');
assert(mask.length() >= line.length());
for (int i = line.length() - 1; i >= 0; i--)
if (line[i] != ' ')
mask[i] = '*';
}
static bool
parse_range(const std::string & spec, column & pair) {
// Parse the range specification spec into pair. Return true if the parse
// was successful, false otherwise (in which case the contents of pair is
// unchanged).
std::string left, right;
if (split(spec, "-", left, right)) {
if (!(is_int(left) and is_int(right)))
return false;
pair.begin = std::atoi(left.c_str());
pair.end = std::atoi(right.c_str());
if (pair.begin > pair.end)
return false;
}
else {
if (!is_int(spec))
return false;
pair.begin = std::atoi(spec.c_str());
pair.end = pair.begin;
}
pair.end++;
return true;
}
static bool
parse_spec(const std::string & spec, column & rows, column & cols) {
// Parse the section spec spec into row and column ranges. Return true if
// the parse was successful, false otherwise (in which case the contents of
// rows and cols is undefined).
std::string left, right;
if (!split(spec, ",", left, right))
return false;
return parse_range(left, rows) and parse_range(right, cols);
}
static void
print_row(
std::ostream & os, const ss_row & row, ccol_cptr columns, const column & col) {
// Write to output stream os the range of columns given in col from the
// spreadsheet row rw; columns contains the spreadsheet column layout.
const char * sep = "";
for (str_indx i = col.begin; i < col.end; i++) {
const column & c = columns[i];
const str_indx
b = std::min(c.begin, row.size()),
e = std::min(c.end, row.size());
assert((b <= e) and (e <= row.size()));
os << sep << row.substr(b, e - b);
sep = " ";
}
os << "\n";
}
static void
print_section(
std::ostream & os,
const spreadsheet ss,
ccol_cptr columns,
cchar_cptr spec) {
// Print the section specified by spec from the spreadsheet ss to the output
// stream os; columns contains the column definitions.
column rows, cols;
if (!parse_spec(std::string(spec), rows, cols)) {
os << "Malformed section spec: " << spec << "\n";
return;
}
str_indx max_row;
for (max_row = 0; ss[max_row].length() != 0; max_row++) { }
str_indx max_col;
for (max_col = 0; columns[max_col].begin != std::string::npos; max_col++) { }
if ((rows.end > max_row) or (cols.end > max_col)) {
os << "Section spec out of bounds: " << spec << "\n";
return;
}
for (str_indx i = rows.begin; i < rows.end; i++)
print_row(os, ss[i], columns, cols);
}
static spreadsheet
read_spreadsheet(std::istream & is, unsigned count) {
// Read the next spreadsheet line from the input stream is and store it as
// the count-th element of the array returned. The last array element is the
// empty string.
ss_row line;
spreadsheet ss;
if (!readline(is, line)) {
line = "";
ss = new ss_row[count + 1];
}
else
ss = read_spreadsheet(is, count + 1);
ss[count] = line;
return ss;
}
static bool
readline(std::istream & is, ss_row & line) {
// Read the next non-blank line from input stream is into line; return true
// if a non-blank line was read.
while (true) {
if (!std::getline(is, line))
return false;
if (line.find_first_not_of(" ") != std::string::npos)
return true;
}
}
static bool
split(
const std::string & str, cchar_cptr sep,
std::string & left, std::string & right) {
// Split the string str at the leftmost occurance of any of the characters in
// sep; store the substring to the left of the separator in left, the
// substring to the right of the separator in right, and return true. Return
// false if str doesn't contain any of the characters in sep; in which case
// the contents of left and right are unchanged.
unsigned c = str.find_first_of(sep);
if (c == std::string::npos)
return false;
left = str.substr(0, c);
c++;
right = str.substr(c, str.length() - c);
return true;
}
// $Log:$
syntax highlighted by Code2HTML, v. 0.9