diff --git a/example/text_io_ex.cpp b/example/text_io_ex.cpp index 663a1de..3a87f55 100644 --- a/example/text_io_ex.cpp +++ b/example/text_io_ex.cpp @@ -32,21 +32,35 @@ using namespace gctl; int main(int argc, char const *argv[]) try { + text_content tc; + tc.load_text("tmp/sample", ".txt", HasColumnName); + tc.info(); + +/* text_content tc("tmp/topo", ".txt", HasColumnName); array x, y, z; tc.get_column(0, x); tc.get_column(1, y); - tc.get_column(2, z); + tc.get_column("elevation", z); std::clog << std::setprecision(11) << z.front() << "\n"; std::clog << x.back() << "," << y.back() << "," << z.back() << "\n"; - display_vector(tc.tags_, std::clog, '\n'); - display_vector(tc.annotates_, std::clog, '\n'); - display_vector(tc.heads_, std::clog, '\n'); + display_vector(tc.get_tags(), std::clog, '\n'); + display_vector(tc.get_annotoations(), std::clog, '\n'); + display_vector(tc.get_head_records(), std::clog, '\n'); - tc.set_delimeter(','); - tc.save_text("out", ".csv"); + _1s_vector s = tc.get_tags(); + s.push_back("Elev = 1000"); + tc.set_tags(s); + tc.save_csv("out"); + + double c = 4.25242153654; + tc.cell(0, 0, c, 12); + std::clog << std::setprecision(12) << tc.cell(0, 0) << "\n"; + + tc.info(); +*/ return 0; } catch(std::exception &e) diff --git a/lib/io/text_io2.cpp b/lib/io/text_io2.cpp index 71aab05..1412e9a 100644 --- a/lib/io/text_io2.cpp +++ b/lib/io/text_io2.cpp @@ -81,6 +81,8 @@ void gctl::text_content::load_text(std::string filename, std::string file_exten, std::getline(infile, tmp_line); if (!tmp_line.empty()) heads_.push_back(tmp_line); } + // 校正头信息行数 + head_num_ = heads_.size(); while (std::getline(infile, tmp_line)) { @@ -142,6 +144,20 @@ void gctl::text_content::load_text(std::string filename, std::string file_exten, table_[i].push_back(empty_cell); } } + + for (size_t i = col_names_.size(); i < col_num_; i++) + { + col_names_.push_back("col-" + std::to_string(i + 1)); + } + + file_ = filename + file_exten; + return; +} + +void gctl::text_content::load_csv(std::string filename, text_head_type_e t) +{ + set_delimeter(','); + load_text(filename, ".csv", t); return; } @@ -165,15 +181,12 @@ void gctl::text_content::save_text(std::string filename, std::string file_exten) outfile << "# " << annotates_[i] << std::endl; } - if (!col_names_.empty()) + outfile << col_names_[0]; + for (size_t j = 1; j < col_names_.size(); j++) { - outfile << col_names_[0]; - for (size_t j = 1; j < col_names_.size(); j++) - { - outfile << deli_sym_ << col_names_[j]; - } - outfile << std::endl; + outfile << deli_sym_ << col_names_[j]; } + outfile << std::endl; for (int i = 0; i < row_num_; i++) { @@ -189,28 +202,104 @@ void gctl::text_content::save_text(std::string filename, std::string file_exten) return; } +void gctl::text_content::save_csv(std::string filename) +{ + set_delimeter(','); + save_text(filename, ".csv"); + return; +} + void gctl::text_content::init_table(int row, int col) { row_num_ = row; col_num_ = col; - lines_.resize(row_num_); table_.resize(row_num_); for (size_t i = 0; i < row_num_; i++) { - lines_[i] = ""; - table_[i].resize(col_num_); for (size_t j = 0; j < col_num_; j++) { table_[i][j].str_ = ""; } } + + col_names_.resize(col_num_); + for (size_t i = 0; i < col_num_; i++) + { + col_names_[i] = "col-" + std::to_string(i + 1); + } return; } -void gctl::text_content::set_column_name(const std::vector &names) +void gctl::text_content::init_table(int row, int col, const std::vector &names) { + init_table(row, col); + set_column_names(names); + return; +} + +void gctl::text_content::set_head_records(const std::vector &heads) +{ + heads_ = heads; + head_num_ = heads_.size(); + return; +} + +void gctl::text_content::set_annotoations(const std::vector &att) +{ + annotates_ = att; + return; +} + +void gctl::text_content::set_tags(const std::vector &tags) +{ + tags_ = tags; + return; +} + +void gctl::text_content::set_column_names(const std::vector &names) +{ + if (col_num_ != col_names_.size()) + { + throw std::runtime_error("[gctl::text_content::set_column_names] Invalid name size."); + } + col_names_ = names; return; +} + +void gctl::text_content::cell(int r, int c, double d, int p) +{ + std::stringstream ss; + if (p != 6) ss.precision(p); + + ss << d; + ss >> table_[r][c].str_; + return; +} + +void gctl::text_content::info() +{ + std::clog << "File: " << file_ << "\n------------\n"; + std::clog << "Head(s): " << head_num_ << "\n"; + std::clog << "Annotation(s): " << annotates_.size() << "\n"; + std::clog << "Tag(s): " << tags_.size() << "\n"; + std::clog << "------------\nColumns:\n============\n"; + + if (col_names_.empty()) + { + for (size_t i = 0; i < col_num_; i++) + { + std::clog << table_[0][i].str_ << " -> " << table_.back()[i].str_ << "\n"; + } + } + else + { + for (size_t i = 0; i < col_num_; i++) + { + std::clog << col_names_[i] << ": " << table_[0][i].str_ << " -> " << table_.back()[i].str_ << "\n"; + } + } + return; } \ No newline at end of file diff --git a/lib/io/text_io2.h b/lib/io/text_io2.h index 6b6d887..6d3fc51 100644 --- a/lib/io/text_io2.h +++ b/lib/io/text_io2.h @@ -57,8 +57,20 @@ namespace gctl NoColumnName, }; - struct text_content + /** + * @brief 文本读写类 + * + * 可以处理的文本数据应该符合下述要求: + * 1. 以'#'开始的行均为注释行,标识符可由用户指定; + * 2. 以'#!'开始的行均为标记行,标识符可由用户指定; + * 3. 文本开始可以包含n行头信息; + * 4. 数据体为一个row*col大小的表格。 + * + */ + class text_content { + private: + std::string file_; // 头信息行数 表格行数 表格列数 int head_num_, row_num_, col_num_; // 注释行起始符 标记行起始符 分割符 @@ -70,6 +82,7 @@ namespace gctl std::vector lines_; std::vector > table_; + public: /** * @brief Construct a new text content object * @@ -118,6 +131,92 @@ namespace gctl */ void set_tag_symbol(char tag_sym){tag_sym_ = tag_sym;} + /** + * @brief 返回头信息行数 + * + * @return 行数 + */ + int head_number(){return head_num_;} + + /** + * @brief 返回行数 + * + * @return 行数 + */ + int row_number(){return row_num_;} + + /** + * @brief 返回列数 + * + * @return 列数 + */ + int col_number(){return col_num_;} + + /** + * @brief 返回行数据 + * + * @note 目前只有load_text函数才会使用lines + * + * @return 返回按行储存的文本内容 + */ + const std::vector& get_lines(){return lines_;} + + /** + * @brief 返回头信息 + * + * @return 头信息 + */ + const std::vector& get_head_records(){return heads_;} + + /** + * @brief 返回注释行 + * + * @return 注释行 + */ + const std::vector& get_annotoations(){return annotates_;} + + /** + * @brief 返回标记行 + * + * @return 标记 + */ + const std::vector& get_tags(){return tags_;} + + /** + * @brief 返回列名称 + * + * @return 列名称 + */ + const std::vector& get_column_names(){return col_names_;} + + /** + * @brief 设置头信息 + * + * @param heads 头信息 + */ + void set_head_records(const std::vector &heads); + + /** + * @brief 设置注释 + * + * @param att 注释 + */ + void set_annotoations(const std::vector &att); + + /** + * @brief 设置标记 + * + * @param tags 标记 + */ + void set_tags(const std::vector &tags); + + /** + * @brief 设置列数据名称 + * + * @param names 列名称 + */ + void set_column_names(const std::vector &names); + /** * @brief 清理字符串向量对象 * @@ -131,15 +230,29 @@ namespace gctl * @param file_exten 文件扩展名 */ void load_text(std::string filename, std::string file_exten = ".txt", text_head_type_e t = NoColumnName); + + /** + * @brief 读入CSV文件 + * + * @param filename 文件名 + */ + void load_csv(std::string filename, text_head_type_e t = HasColumnName); /** - * @brief 将内容写入文件文件 + * @brief 将内容写入文件 * * @param filename 文件名 * @param file_exten 文件扩展名 */ void save_text(std::string filename, std::string file_exten = ".txt"); + /** + * @brief 将内容写入CSV文件 + * + * @param filename 文件名(无后缀) + */ + void save_csv(std::string filename); + /** * @brief 初始化表格 * @@ -149,11 +262,13 @@ namespace gctl void init_table(int row, int col); /** - * @brief 设置列数据名称 + * @brief 初始化表格 * + * @param row 行数 + * @param col 列数 * @param names 列名称 */ - void set_column_name(const std::vector &names); + void init_table(int row, int col, const std::vector &names); /** * @brief 填充列 @@ -164,6 +279,15 @@ namespace gctl */ template void fill_column(int idx, const array &data); + /** + * @brief 填充列 + * + * @tparam T 数据类型 + * @param name 列名称 + * @param data 列数据 + */ + template void fill_column(std::string name, const array &data); + /** * @brief 填充行 * @@ -181,6 +305,15 @@ namespace gctl * @param data 列数据 */ template void get_column(int idx, array &data); + + /** + * @brief 获取列数据 + * + * @tparam T 数据类型 + * @param name 列名称 + * @param data 列数据 + */ + template void get_column(std::string name, array &data); /** * @brief 获取行数据 @@ -190,6 +323,42 @@ namespace gctl * @param data 行数据 */ template void get_row(int idx, array &data); + + /** + * @brief 获取表格单元数据 + * + * @tparam T 数据类型 + * @param r 行号 + * @param c 列号 + * @return T 单元数据 + */ + template T cell(int r, int c){return table_[r][c].value();} + + /** + * @brief 填充表格单元数据 + * + * @tparam T 数据类型 + * @param r 行号 + * @param c 列号 + * @param d 数据 + */ + template void cell(int r, int c, T d){table_[r][c].value(d); return;} + + /** + * @brief 填充表格单元数据 double类型专用 + * + * @param r 行号 + * @param c 列号 + * @param d 数据 + * @param p 有效数字位数 + */ + void cell(int r, int c, double d, int p); + + /** + * @brief 返回表格信息 + * + */ + void info(); }; template @@ -207,6 +376,27 @@ namespace gctl return; } + template + void text_content::fill_column(std::string name, const array &data) + { + if (col_names_.empty()) + { + throw std::runtime_error("[gctl::text_content::fill_column] No column names instored."); + } + + for (size_t i = 0; i < col_names_.size(); i++) + { + if (col_names_[i] == name) + { + fill_column(i, data); + return; + } + } + + throw std::runtime_error("[gctl::text_content::fill_column] No column found by the input name."); + return; + } + template void text_content::fill_row(int idx, const array &data) { @@ -238,6 +428,27 @@ namespace gctl return; } + template + void text_content::get_column(std::string name, array &data) + { + if (col_names_.empty()) + { + throw std::runtime_error("[gctl::text_content::get_column] No column names instored."); + } + + for (size_t i = 0; i < col_names_.size(); i++) + { + if (col_names_[i] == name) + { + get_column(i, data); + return; + } + } + + throw std::runtime_error("[gctl::text_content::get_column] No column found by the input name."); + return; + } + template void text_content::get_row(int idx, array &data) {