/******************************************************** * ██████╗ ██████╗████████╗██╗ * ██╔════╝ ██╔════╝╚══██╔══╝██║ * ██║ ███╗██║ ██║ ██║ * ██║ ██║██║ ██║ ██║ * ╚██████╔╝╚██████╗ ██║ ███████╗ * ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝ * Geophysical Computational Tools & Library (GCTL) * * Copyright (c) 2023 Yi Zhang (yizhang-geo@zju.edu.cn) * * GCTL is distributed under a dual licensing scheme. You can redistribute * it and/or modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 2 * of the License, or (at your option) any later version. You should have * received a copy of the GNU Lesser General Public License along with this * program. If not, see . * * If the terms and conditions of the LGPL v.2. would prevent you from using * the GCTL, please consider the option to obtain a commercial license for a * fee. These licenses are offered by the GCTL's original author. As a rule, * licenses are provided "as-is", unlimited in time for a one time fee. Please * send corresponding requests to: yizhang-geo@zju.edu.cn. Please do not forget * to include some description of your company and the realm of its activities. * Also add information on how to contact you by electronic and paper mail. ******************************************************/ #ifndef _GCTL_TEXT_IO_H #define _GCTL_TEXT_IO_H // library's head file #include "../core.h" #include "../utility.h" #include "../geometry.h" // system head file #include "initializer_list" namespace gctl { struct text_descriptor { int head_num_, float_psn_; // 注释行起始符 标记行起始符 分割符 char att_sym_, tag_sym_, delimiter_; // 文件扩展名 std::string file_name_, file_ext_, col_str_; // 注释行 标记行 std::vector head_strs_, annotates_, tags_; text_descriptor(); ~text_descriptor(); /** * @brief Construct a new text descriptor object * * @param filename 文件名 * @param file_exten 文件扩展名 * @param col_order 列数据索引字符串 * @param att_sym 注释行起始符 * @param tag_sym 标记行起始符 * @param deli 分割符 */ text_descriptor(std::string filename, std::string file_exten = ".txt", std::string col_order = "0,1,2", char deli = ' ', char att_sym = '#', char tag_sym = '>', int h_num = 0, int io_psn = 6); /** * @brief 设置文件对象 * * @param filename 文件名 * @param file_exten 文件扩展名 * @param att_sym 注释行起始符 * @param tag_sym 标记行起始符 * @param deli 分割符 */ void set(std::string filename = "Untitled", std::string file_exten = ".txt", std::string col_order = "0,1,2", char deli = ' ', char att_sym = '#', char tag_sym = '>', int h_num = 0, int io_psn = 6); /** * @brief 清理向量 * */ void clear(); /** * @brief 设置浮点输出精度 * * @param psn 有效数字位数 */ void set_float_precision(int psn); /** * @brief 设置头信息行数 * * @param n 行数 */ void set_head_number(int n); /** * @brief 设置注释行标识符 * * @param sym 标识符 */ void set_annotation_symbol(char sym); /** * @brief 设置标志行标识符 * * @param sym 标识符 */ void set_tag_symbol(char sym); /** * @brief 设置列分隔符 * * @param sym 标识符 */ void set_column_delimeter(char sym); /** * @brief 设置文件扩展名 * * @param ext_s 扩展名 */ void set_file_extension(std::string ext_s); /** * @brief 设置列索引列表 * * @param sym 标识符 */ void set_column_order(std::string col_s); }; /** * @brief 从文本文件读入行到一维向量 * * @note 文件中的每一行为向量中的一个元素,对应的元素类型需支持>>操作符(一般通过操作符重载实现) * * @param desc 文件描述对象(包括了文件名,描述符等信息) * @param out_vec 返回的一维向量 * * @tparam T 模版向量类型 */ template void read_text2vector(text_descriptor &desc, std::vector &out_vec) { std::ifstream infile; open_infile(infile, desc.file_name_, desc.file_ext_); // clear cleanup old table out_vec.clear(); desc.clear(); std::string tmp_line; std::stringstream tmp_ss; for (int i = 0; i < desc.head_num_; i++) { getline(infile, tmp_line); desc.head_strs_.push_back(tmp_line); } T tmp_d; while (std::getline(infile, tmp_line)) { if (tmp_line[0] == desc.att_sym_) { tmp_line = tmp_line.substr(1); tmp_line.erase(0, tmp_line.find_first_not_of(" \t")); tmp_line.erase(tmp_line.find_last_not_of(" \t") + 1); desc.annotates_.push_back(tmp_line); } else if (tmp_line[0] == desc.tag_sym_) { tmp_line = tmp_line.substr(1); tmp_line.erase(0, tmp_line.find_first_not_of(" \t")); tmp_line.erase(tmp_line.find_last_not_of(" \t") + 1); desc.tags_.push_back(tmp_line); } else { tmp_ss.clear(); tmp_ss.str(tmp_line); tmp_ss >> tmp_d; if (tmp_ss.fail()) { throw gctl::runtime_error("[gctl::read_text2vector] Fail to parse the line: " + tmp_line); } out_vec.push_back(tmp_d); } } infile.close(); return; } /** * @brief 从文本文件读入行到一维数组 * * @note 文件中的每一行为向量中的一个元素,对应的元素类型需支持>>操作符(一般通过操作符重载实现) * * @param desc 文件描述对象(包括了文件名,描述符等信息) * @param out_vec 返回的一维向量 * * @tparam T 模版向量类型 */ template void read_text2array(text_descriptor &desc, array &out_arr) { std::ifstream infile; open_infile(infile, desc.file_name_, desc.file_ext_); // clear cleanup old table out_arr.clear(); desc.clear(); std::string tmp_line; std::stringstream tmp_ss; for (int i = 0; i < desc.head_num_; i++) { getline(infile, tmp_line); desc.head_strs_.push_back(tmp_line); } size_t l_count = 0; while (std::getline(infile, tmp_line)) { if (tmp_line[0] == desc.att_sym_) { tmp_line = tmp_line.substr(1); tmp_line.erase(0, tmp_line.find_first_not_of(" \t")); tmp_line.erase(tmp_line.find_last_not_of(" \t") + 1); desc.annotates_.push_back(tmp_line); } else if (tmp_line[0] == desc.tag_sym_) { tmp_line = tmp_line.substr(1); tmp_line.erase(0, tmp_line.find_first_not_of(" \t")); tmp_line.erase(tmp_line.find_last_not_of(" \t") + 1); desc.tags_.push_back(tmp_line); } else l_count++; } // reset the file pointer infile.clear(); infile.seekg(0); for (int i = 0; i < desc.head_num_; i++) { getline(infile, tmp_line); } out_arr.resize(l_count); l_count = 0; T tmp_d; while (std::getline(infile, tmp_line)) { if (tmp_line[0] != desc.att_sym_ && tmp_line[0] != desc.tag_sym_) { tmp_ss.clear(); tmp_ss.str(tmp_line); tmp_ss >> tmp_d; if (tmp_ss.fail()) { throw gctl::runtime_error("[gctl::read_text2vector] Fail to parse the line: " + tmp_line); } out_arr[l_count] = tmp_d; l_count++; } } infile.close(); return; } /** * @brief 保存一维向量到文本文件 * * @note 向量中的每个元素保存为一行,对应的元素类型需支持<<操作符(一般通过操作符重载实现) * * @param[in] desc 文件描述对象(包括了文件名,描述符等信息) * @param[in] in_vec 待输出的向量 * * @tparam T 模版向量类型 */ template void save_vector2text(const text_descriptor &desc, const std::vector &in_vec) { std::ofstream outfile; open_outfile(outfile, desc.file_name_, desc.file_ext_); for (int i = 0; i < desc.head_strs_.size(); i++) { outfile << desc.head_strs_[i] << std::endl; } for (int i = 0; i < desc.tags_.size(); i++) { outfile << "> " << desc.tags_[i] << std::endl; } for (int i = 0; i < desc.annotates_.size(); i++) { outfile << "# " << desc.annotates_[i] << std::endl; } for (int i = 0; i < in_vec.size(); i++) { outfile << std::setprecision(desc.float_psn_) << in_vec[i] << std::endl; } outfile.close(); return; } /** * @brief 保存一维数组到文本文件 * * @note 向量中的每个元素保存为一行,对应的元素类型需支持<<操作符(一般通过操作符重载实现) * * @param[in] desc 文件描述对象(包括了文件名,描述符等信息) * @param[in] in_arr 待输出的向量 * * @tparam T 模版向量类型 */ template void save_array2text(const text_descriptor &desc, const array &in_arr) { std::ofstream outfile; open_outfile(outfile, desc.file_name_, desc.file_ext_); for (int i = 0; i < desc.head_strs_.size(); i++) { outfile << desc.head_strs_[i] << std::endl; } for (int i = 0; i < desc.tags_.size(); i++) { outfile << "> " << desc.tags_[i] << std::endl; } for (int i = 0; i < desc.annotates_.size(); i++) { outfile << "# " << desc.annotates_[i] << std::endl; } for (int i = 0; i < in_arr.size(); i++) { outfile << std::setprecision(desc.float_psn_) << in_arr[i] << std::endl; } outfile.close(); return; } template void read_text2vector2d(text_descriptor &desc, std::vector> &out_vec2d) { std::ifstream infile; open_infile(infile, desc.file_name_, desc.file_ext_); // clear old table if (!out_vec2d.empty()) destroy_vector(out_vec2d); desc.annotates_.reserve(1024); desc.head_strs_.reserve(1024); desc.tags_.reserve(1024); std::string tmp_line; std::vector tmp_row; for (size_t i = 0; i < desc.head_num_; i++) { getline(infile, tmp_line); desc.head_strs_.push_back(tmp_line); } while (getline(infile, tmp_line)) { if (tmp_line[0] == desc.att_sym_) { tmp_line = tmp_line.substr(1); tmp_line.erase(0, tmp_line.find_first_not_of(" \t")); tmp_line.erase(tmp_line.find_last_not_of(" \t") + 1); desc.annotates_.push_back(tmp_line); } else if (tmp_line[0] == desc.tag_sym_) { tmp_line = tmp_line.substr(1); tmp_line.erase(0, tmp_line.find_first_not_of(" \t")); tmp_line.erase(tmp_line.find_last_not_of(" \t") + 1); desc.tags_.push_back(tmp_line); } else { tmp_row.clear(); parse_string_to_vector(tmp_line, desc.delimiter_, tmp_row); out_vec2d.push_back(tmp_row); } } infile.close(); return; } template void save_vector2d2text(const text_descriptor &desc, const std::vector> &out_vec2d, matrix_order_e order_type = RowMajor) { std::ofstream outfile; open_outfile(outfile, desc.file_name_, desc.file_ext_); for (int i = 0; i < desc.head_strs_.size(); i++) { outfile << desc.head_strs_[i] << std::endl; } for (int i = 0; i < desc.tags_.size(); i++) { outfile << "> " << desc.tags_[i] << std::endl; } for (int i = 0; i < desc.annotates_.size(); i++) { outfile << "# " << desc.annotates_[i] << std::endl; } if (order_type == RowMajor) { for (int i = 0; i < out_vec2d.size(); i++) { outfile << std::setprecision(desc.float_psn_) << out_vec2d[i][0]; for (int j = 1; j < out_vec2d.at(i).size(); j++) { outfile << std::setprecision(desc.float_psn_) << desc.delimiter_ << out_vec2d[i][j]; } outfile << std::endl; } outfile.close(); return; } for (int i = 0; i < out_vec2d[0].size(); i++) { outfile << std::setprecision(desc.float_psn_) << out_vec2d[0][i]; for (int j = 1; j < out_vec2d.size(); j++) { outfile << std::setprecision(desc.float_psn_) << desc.delimiter_ << out_vec2d[j][i]; } outfile << std::endl; } outfile.close(); return; } template void save_matrix2text(const text_descriptor &desc, const matrix &out_arr2d, matrix_order_e order_type = RowMajor) { std::ofstream outfile; open_outfile(outfile, desc.file_name_, desc.file_ext_); for (int i = 0; i < desc.head_strs_.size(); i++) { outfile << desc.head_strs_[i] << std::endl; } for (int i = 0; i < desc.tags_.size(); i++) { outfile << "> " << desc.tags_[i] << std::endl; } for (int i = 0; i < desc.annotates_.size(); i++) { outfile << "# " << desc.annotates_[i] << std::endl; } if (order_type == RowMajor) { for (int i = 0; i < out_arr2d.row_size(); i++) { outfile << std::setprecision(desc.float_psn_) << out_arr2d[i][0]; for (int j = 1; j < out_arr2d.col_size(); j++) { outfile << std::setprecision(desc.float_psn_) << desc.delimiter_ << out_arr2d[i][j]; } outfile << std::endl; } outfile.close(); return; } for (int i = 0; i < out_arr2d.col_size(); i++) { outfile << std::setprecision(desc.float_psn_) << out_arr2d[0][i]; for (int j = 1; j < out_arr2d.row_size(); j++) { outfile << std::setprecision(desc.float_psn_) << desc.delimiter_ << out_arr2d[j][i]; } outfile << std::endl; } outfile.close(); return; } template void read_text2vectors(text_descriptor &desc, std::vector &out_vec) { std::string tmp_line, tmp_str, tmp_str2; std::stringstream tmp_ss; std::ifstream infile; open_infile(infile, desc.file_name_, desc.file_ext_); // clear cleanup old table if (!out_vec.empty()) destroy_vector(out_vec); tmp_ss.clear(); tmp_ss.str(desc.col_str_); // get the first index separated by comma std::getline(tmp_ss, tmp_str, ','); // get input column index int col_id; tmp_ss.clear(); tmp_ss.str(tmp_str); tmp_ss >> col_id; if (col_id < 0) { throw runtime_error("[gctl::read_text2vectors] Invalid column index."); } for (int i = 0; i < desc.head_num_; i++) { getline(infile, tmp_line); desc.head_strs_.push_back(tmp_line); } T tmp_d; if (desc.delimiter_ != ' ') { while (std::getline(infile, tmp_line)) { if (tmp_line[0] == desc.att_sym_) { tmp_line = tmp_line.substr(1); tmp_line.erase(0, tmp_line.find_first_not_of(" \t")); tmp_line.erase(tmp_line.find_last_not_of(" \t") + 1); desc.annotates_.push_back(tmp_line); } else if (tmp_line[0] == desc.tag_sym_) { tmp_line = tmp_line.substr(1); tmp_line.erase(0, tmp_line.find_first_not_of(" \t")); tmp_line.erase(tmp_line.find_last_not_of(" \t") + 1); desc.tags_.push_back(tmp_line); } else { // replace all delimiters to spaces tmp_str2 = desc.delimiter_; replace_all(tmp_str, tmp_line, tmp_str2, " "); tmp_ss.clear(); tmp_ss.str(tmp_str); // Skip the first col_id elements for (int i = 0; i < col_id; i++) { tmp_ss >> tmp_str2; } // convert the target object tmp_ss >> tmp_d; if (tmp_ss.fail()) { throw runtime_error("[gctl::read_text2vectors] Fail to parse the line: " + tmp_line); } out_vec.push_back(tmp_d); } } } else { while (std::getline(infile, tmp_line)) { if (tmp_line[0] == desc.att_sym_) { tmp_line = tmp_line.substr(1); tmp_line.erase(0, tmp_line.find_first_not_of(" \t")); tmp_line.erase(tmp_line.find_last_not_of(" \t") + 1); desc.annotates_.push_back(tmp_line); } else if (tmp_line[0] == desc.tag_sym_) { tmp_line = tmp_line.substr(1); tmp_line.erase(0, tmp_line.find_first_not_of(" \t")); tmp_line.erase(tmp_line.find_last_not_of(" \t") + 1); desc.tags_.push_back(tmp_line); } else { tmp_ss.clear(); tmp_ss.str(tmp_line); // Skip the first col_id elements for (int i = 0; i < col_id; i++) { tmp_ss >> tmp_str2; } // convert the target object tmp_ss >> tmp_d; if (tmp_ss.fail()) { throw runtime_error("[gctl::read_text2vectors] Fail to parse the line: " + tmp_line); } out_vec.push_back(tmp_d); } } } infile.close(); return; } template void read_text2vectors(text_descriptor &desc, std::vector &out_vec, std::vector&... rest) { std::string tmp_line, tmp_str, tmp_str2; std::stringstream tmp_ss; std::ifstream infile; open_infile(infile, desc.file_name_, desc.file_ext_); // clear cleanup old table if (!out_vec.empty()) destroy_vector(out_vec); tmp_ss.clear(); tmp_ss.str(desc.col_str_); // get the first index separated by comma std::getline(tmp_ss, tmp_str, ','); // get input column index int col_id; tmp_ss.clear(); tmp_ss.str(tmp_str); tmp_ss >> col_id; if (col_id < 0) { throw runtime_error("[gctl::read_text2vectors] Invalid column index."); } int position = desc.col_str_.find_first_of(','); std::string tmp_order = desc.col_str_.substr(position+1, desc.col_str_.length()); desc.set_column_order(tmp_order); for (int i = 0; i < desc.head_num_; i++) { getline(infile, tmp_line); desc.head_strs_.push_back(tmp_line); } T tmp_d; if (desc.delimiter_ != ' ') { while (std::getline(infile, tmp_line)) { if (tmp_line[0] == desc.att_sym_) { tmp_line = tmp_line.substr(1); tmp_line.erase(0, tmp_line.find_first_not_of(" \t")); tmp_line.erase(tmp_line.find_last_not_of(" \t") + 1); desc.annotates_.push_back(tmp_line); } else if (tmp_line[0] == desc.tag_sym_) { tmp_line = tmp_line.substr(1); tmp_line.erase(0, tmp_line.find_first_not_of(" \t")); tmp_line.erase(tmp_line.find_last_not_of(" \t") + 1); desc.tags_.push_back(tmp_line); } else { // replace all delimiters to spaces tmp_str2 = desc.delimiter_; replace_all(tmp_str, tmp_line, tmp_str2, " "); tmp_ss.clear(); tmp_ss.str(tmp_str); // Skip the first col_id elements for (int i = 0; i < col_id; i++) { tmp_ss >> tmp_str2; } // convert the target object tmp_ss >> tmp_d; if (tmp_ss.fail()) { throw runtime_error("[gctl::read_text2vectors] Fail to parse the line: " + tmp_line); } out_vec.push_back(tmp_d); } } } else { while (std::getline(infile, tmp_line)) { if (tmp_line[0] == desc.att_sym_) { tmp_line = tmp_line.substr(1); tmp_line.erase(0, tmp_line.find_first_not_of(" \t")); tmp_line.erase(tmp_line.find_last_not_of(" \t") + 1); desc.annotates_.push_back(tmp_line); } else if (tmp_line[0] == desc.tag_sym_) { tmp_line = tmp_line.substr(1); tmp_line.erase(0, tmp_line.find_first_not_of(" \t")); tmp_line.erase(tmp_line.find_last_not_of(" \t") + 1); desc.tags_.push_back(tmp_line); } else { tmp_ss.clear(); tmp_ss.str(tmp_line); // Skip the first col_id elements for (int i = 0; i < col_id; i++) { tmp_ss >> tmp_str2; } // convert the target object tmp_ss >> tmp_d; if (tmp_ss.fail()) { throw runtime_error("[gctl::read_text2vectors] Fail to parse the line: " + tmp_line); } out_vec.push_back(tmp_d); } } } infile.close(); read_text2vectors(desc, rest...); return; } template void save_vectors2text(std::string filename, char delimiter, char annotate, std::vector *head_ptr, std::vector *content_ptr, const std::vector &in_vec) { std::ofstream outfile; open_matched_outfile(outfile, filename, ".txt,.dat,.xyz,.csv"); if (in_vec.empty()) { GCTL_ShowWhatError("The input vector is empty. From save_vectors2text(...)", GCTL_WARNING_ERROR, 0, 0, 0); } if (content_ptr == nullptr) { content_ptr = new std::vector(in_vec.size()); for (int i = 0; i < content_ptr->size(); i++) { content_ptr->at(i) = ""; } } int old_row = content_ptr->size(); int new_row = in_vec.size(); // add in_vec to content_ptr std::string tmp_str, tmp_str2, nan_str = "nan"; std::stringstream tmp_ss; if (old_row < new_row) // 当前输入的数组长度长于现有的字符串数组长度 在当前字符串后面补足 { tmp_str2 = ""; tmp_ss.clear(); tmp_ss << content_ptr->at(0); while (std::getline(tmp_ss, tmp_str, delimiter)) { tmp_str2 += (nan_str + delimiter); } for (int i = 0; i < (new_row-old_row); i++) { content_ptr->push_back(tmp_str2); } for (int i = 0; i < new_row; i++) { tmp_ss.clear(); tmp_ss << in_vec[i]; while(tmp_ss >> tmp_str) { content_ptr->at(i) += (tmp_str + delimiter); } } } else if (old_row > new_row) { for (int i = 0; i < new_row; i++) { tmp_ss.clear(); tmp_ss << in_vec[i]; while(tmp_ss >> tmp_str) { content_ptr->at(i) += (tmp_str + delimiter); } } tmp_str2 = ""; tmp_ss.clear(); tmp_ss << in_vec[0]; while(tmp_ss >> tmp_str) { tmp_str2 += (nan_str + delimiter); } for (int i = new_row; i < old_row; i++) { content_ptr->at(i) += tmp_str2; } } else { for (int i = 0; i < new_row; i++) { tmp_ss.clear(); tmp_ss << in_vec[i]; while(tmp_ss >> tmp_str) { content_ptr->at(i) += (tmp_str + delimiter); } } } // start writing file if (head_ptr != nullptr) { for (int i = 0; i < head_ptr->size(); ++i) { outfile << annotate << " " << head_ptr->at(i) << std::endl; } } for (int i = 0; i < content_ptr->size(); i++) { tmp_str = content_ptr->at(i).substr(0, content_ptr->at(i).length()-1); outfile << tmp_str << std::endl; } destroy_vector(*content_ptr); outfile.close(); return; } template void save_vectors2text(std::string filename, char delimiter, char annotate, std::vector *head_ptr, std::vector *content_ptr, const std::vector &in_vec, const std::vector&... rest) { if (in_vec.empty()) { GCTL_ShowWhatError("The input vector is empty. From save_vectors2text(...)", GCTL_WARNING_ERROR, 0, 0, 0); } if (content_ptr == nullptr) { content_ptr = new std::vector(in_vec.size()); for (int i = 0; i < content_ptr->size(); i++) { content_ptr->at(i) = ""; } } int old_row = content_ptr->size(); int new_row = in_vec.size(); // add in_vec to content_ptr std::string tmp_str, tmp_str2, nan_str = "nan"; std::stringstream tmp_ss; if (old_row < new_row) // 当前输入的数组长度长于现有的字符串数组长度 在当前字符串后面补足 { tmp_str2 = ""; tmp_ss.clear(); tmp_ss << content_ptr->at(0); while (std::getline(tmp_ss, tmp_str, delimiter)) { tmp_str2 += (nan_str + delimiter); } for (int i = 0; i < (new_row-old_row); i++) { content_ptr->push_back(tmp_str2); } for (int i = 0; i < new_row; i++) { tmp_ss.clear(); tmp_ss << in_vec[i]; while(tmp_ss >> tmp_str) { content_ptr->at(i) += (tmp_str + delimiter); } } } else if (old_row > new_row) { for (int i = 0; i < new_row; i++) { tmp_ss.clear(); tmp_ss << in_vec[i]; while(tmp_ss >> tmp_str) { content_ptr->at(i) += (tmp_str + delimiter); } } tmp_str2 = ""; tmp_ss.clear(); tmp_ss << in_vec[0]; while(tmp_ss >> tmp_str) { tmp_str2 += (nan_str + delimiter); } for (int i = new_row; i < old_row; i++) { content_ptr->at(i) += tmp_str2; } } else { for (int i = 0; i < new_row; i++) { tmp_ss.clear(); tmp_ss << in_vec[i]; while(tmp_ss >> tmp_str) { content_ptr->at(i) += (tmp_str + delimiter); } } } save_vectors2text(filename, delimiter, annotate, head_ptr, content_ptr, rest...); return; } template void save_arrays2text(std::string filename, char delimiter, char annotate, std::vector *head_ptr, std::vector *content_ptr, const array &in_vec) { std::ofstream outfile; open_matched_outfile(outfile, filename, ".txt,.dat,.xyz,.csv"); if (in_vec.empty()) { GCTL_ShowWhatError("The input array is empty. From save_arrays2text(...)", GCTL_WARNING_ERROR, 0, 0, 0); } if (content_ptr == nullptr) { content_ptr = new std::vector(in_vec.size()); for (int i = 0; i < content_ptr->size(); i++) { content_ptr->at(i) = ""; } } int old_row = content_ptr->size(); int new_row = in_vec.size(); // add in_vec to content_ptr std::string tmp_str, tmp_str2, nan_str = "nan"; std::stringstream tmp_ss; if (old_row < new_row) // 当前输入的数组长度长于现有的字符串数组长度 在当前字符串后面补足 { tmp_str2 = ""; tmp_ss.clear(); tmp_ss << content_ptr->at(0); while (std::getline(tmp_ss, tmp_str, delimiter)) { tmp_str2 += (nan_str + delimiter); } for (int i = 0; i < (new_row-old_row); i++) { content_ptr->push_back(tmp_str2); } for (int i = 0; i < new_row; i++) { tmp_ss.clear(); tmp_ss << in_vec[i]; while(tmp_ss >> tmp_str) { content_ptr->at(i) += (tmp_str + delimiter); } } } else if (old_row > new_row) { for (int i = 0; i < new_row; i++) { tmp_ss.clear(); tmp_ss << in_vec[i]; while(tmp_ss >> tmp_str) { content_ptr->at(i) += (tmp_str + delimiter); } } tmp_str2 = ""; tmp_ss.clear(); tmp_ss << in_vec[0]; while(tmp_ss >> tmp_str) { tmp_str2 += (nan_str + delimiter); } for (int i = new_row; i < old_row; i++) { content_ptr->at(i) += tmp_str2; } } else { for (int i = 0; i < new_row; i++) { tmp_ss.clear(); tmp_ss << in_vec[i]; while(tmp_ss >> tmp_str) { content_ptr->at(i) += (tmp_str + delimiter); } } } if (head_ptr != nullptr) { for (int i = 0; i < head_ptr->size(); ++i) { outfile << annotate << " " << head_ptr->at(i) << std::endl; } } for (int i = 0; i < content_ptr->size(); i++) { tmp_str = content_ptr->at(i).substr(0, content_ptr->at(i).length()-1); outfile << tmp_str << std::endl; } destroy_vector(*content_ptr); outfile.close(); return; } template void save_arrays2text(std::string filename, char delimiter, char annotate, std::vector *head_ptr, std::vector *content_ptr, const array &in_vec, const array&... rest) { if (in_vec.empty()) { GCTL_ShowWhatError("The input array is empty. From save_arrays2text(...)", GCTL_WARNING_ERROR, 0, 0, 0); } if (content_ptr == nullptr) { content_ptr = new std::vector(in_vec.size()); for (int i = 0; i < content_ptr->size(); i++) { content_ptr->at(i) = ""; } } int old_row = content_ptr->size(); int new_row = in_vec.size(); // add in_vec to content_ptr std::string tmp_str, tmp_str2, nan_str = "nan"; std::stringstream tmp_ss; if (old_row < new_row) // 当前输入的数组长度长于现有的字符串数组长度 在当前字符串后面补足 { tmp_str2 = ""; tmp_ss.clear(); tmp_ss << content_ptr->at(0); while (std::getline(tmp_ss, tmp_str, delimiter)) { tmp_str2 += (nan_str + delimiter); } for (int i = 0; i < (new_row-old_row); i++) { content_ptr->push_back(tmp_str2); } for (int i = 0; i < new_row; i++) { tmp_ss.clear(); tmp_ss << in_vec[i]; while(tmp_ss >> tmp_str) { content_ptr->at(i) += (tmp_str + delimiter); } } } else if (old_row > new_row) { for (int i = 0; i < new_row; i++) { tmp_ss.clear(); tmp_ss << in_vec[i]; while(tmp_ss >> tmp_str) { content_ptr->at(i) += (tmp_str + delimiter); } } tmp_str2 = ""; tmp_ss.clear(); tmp_ss << in_vec[0]; while(tmp_ss >> tmp_str) { tmp_str2 += (nan_str + delimiter); } for (int i = new_row; i < old_row; i++) { content_ptr->at(i) += tmp_str2; } } else { for (int i = 0; i < new_row; i++) { tmp_ss.clear(); tmp_ss << in_vec[i]; while(tmp_ss >> tmp_str) { content_ptr->at(i) += (tmp_str + delimiter); } } } save_arrays2text(filename, delimiter, annotate, head_ptr, content_ptr, rest...); return; } /** * @brief 从文本文件中读入指定的行到字符串数组 * * @param file_desc 文件描述对象 * @param out_vec 返回的字符串数组 * @param start_line 起始行,若start_line和end_line同为0则读取整个文件 * @param end_line 终止行,若start_line和end_line同为0则读取整个文件 */ void read_text_lines(text_descriptor &file_desc, std::vector &out_vec, int start_line = 0, int end_line = 0); /** * @brief 从文本文件中读入注释行到字符串数组 * * @note 读取的字符串不包含标志符 * * @param[in] filename 文件名 * @param[in] file_ext 文件名后缀 * @param out_vec 返回的字符串数组 * @param[in] annotate 注释行的标志符,默认为#号 */ void read_annotations(std::string filename, std::vector &out_vec, std::string file_ext = ".txt", char annotate = '#'); /** * @brief 从二维向量读入直角坐标系的点数组 * * @param[in] data_table 二维向量 * @param out_ps 返回的点数组 * @param[in] order 三维坐标的点列序列 */ void get_xyz_points(const _2d_vector &data_table, array &out_ps, std::string order = "0,1,2"); /** * @brief 从二维向量读入直角坐标系的点数组 * * @param[in] data_table 二维向量 * @param out_ps 返回的点数组 * @param[in] order 三维坐标的点列序列 */ void get_xyz_points(const _2d_vector &data_table, array &out_ps, std::string order = "0,1,2"); /** * @brief 从文件读入直角坐标系的点数组 * * @param[in] filename 文件名 * @param out_ps 返回的点数组 * @param[in] order 三维坐标的点列序列 * @param[in] delimiter 分隔符 * @param[in] annotate 标注行符号 */ void get_xyz_points(std::string filename, array &out_ps, text_descriptor &desc, std::string order = "0,1,2", std::string file_ext = ".txt,.dat,.xyz,.csv"); /** * @brief 从文件读入球坐标系的点数组 * * @param[in] filename 文件名 * @param out_ps 返回的点数组 * @param[in] order 三维坐标的点列序列 * @param[in] delimiter 分隔符 * @param[in] annotate 标注行符号 */ void get_xyz_points(std::string filename, array &out_ps, text_descriptor &desc, std::string order = "0,1,2", std::string file_ext = ".txt,.dat,.xyz,.csv"); /** * @brief 读取数据列 * * @param[in] data_table 二维数据向量 * @param[in] dat_val 输入的数据数组列表 * @param[in] dat_col 输入的数据列(数据列不足时会按从左到右顺序读入) */ void get_data_column(const _2d_vector &data_table, std::initializer_list*> dat_val, std::initializer_list dat_col); /** * @brief 读取数据列 * * @param filename 输入文件名 * @param[in] dat_val 输入的数据数组列表 * @param[in] dat_col 输入的数据列(数据列不足时会按从左到右顺序读入) * @param[in] delimiter 元素分割符 * @param[in] annotate 注释行符号 * @param[in] head_record 头信息行数 */ void get_data_column(std::string filename, std::initializer_list*> dat_val, std::initializer_list dat_col, text_descriptor &desc, std::string file_ext = ".txt,.dat,.xyz,.csv"); /** * @brief 保存数据列 * * @param outfile 输出文件流 * @param[in] dat_val 输出的数据数组列表 */ void save_data_column(std::ofstream &outfile, std::initializer_list*> dat_val, std::initializer_list dat_name, char delimiter = ' ', int precision = GCTL_PRECISION); /** * @brief 保存数据列(std向量类型的重载) * * @param outfile 输出文件流 * @param[in] dat_val 输出的数据数组列表 */ void save_data_column(std::ofstream &outfile, std::initializer_list*> dat_val, std::initializer_list dat_name, char delimiter = ' ', int precision = GCTL_PRECISION); } #endif //_GCTL_TEXT_IO_H