gctl/lib/io/text_io.h
2024-09-16 14:28:08 +08:00

1273 lines
32 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/********************************************************
* ██████╗ ██████╗████████╗██╗
* ██╔════╝ ██╔════╝╚══██╔══╝██║
* ██║ ███╗██║ ██║ ██║
* ██║ ██║██║ ██║ ██║
* ╚██████╔╝╚██████╗ ██║ ███████╗
* ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
* 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 <http://www.gnu.org/licenses/>.
*
* 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<std::string> 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 <typename T>
void read_text2vector(text_descriptor &desc, std::vector<T> &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 <typename T>
void read_text2array(text_descriptor &desc, array<T> &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 <typename T>
void save_vector2text(const text_descriptor &desc, const std::vector<T> &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 <typename T>
void save_array2text(const text_descriptor &desc, const array<T> &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 <typename T>
void read_text2vector2d(text_descriptor &desc, std::vector<std::vector<T>> &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<T> 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 <typename T>
void save_vector2d2text(const text_descriptor &desc, const std::vector<std::vector<T>> &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 <typename T>
void save_matrix2text(const text_descriptor &desc, const matrix<T> &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 <typename T>
void read_text2vectors(text_descriptor &desc, std::vector<T> &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 <typename T, typename... Args>
void read_text2vectors(text_descriptor &desc, std::vector<T> &out_vec, std::vector<Args>&... 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 <typename T>
void save_vectors2text(std::string filename, char delimiter, char annotate,
std::vector<std::string> *head_ptr, std::vector<std::string> *content_ptr,
const std::vector<T> &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<std::string>(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 <typename T, typename... Args>
void save_vectors2text(std::string filename, char delimiter, char annotate,
std::vector<std::string> *head_ptr, std::vector<std::string> *content_ptr,
const std::vector<T> &in_vec, const std::vector<Args>&... 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<std::string>(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 <typename T>
void save_arrays2text(std::string filename, char delimiter, char annotate,
std::vector<std::string> *head_ptr, std::vector<std::string> *content_ptr,
const array<T> &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<std::string>(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 <typename T, typename... Args>
void save_arrays2text(std::string filename, char delimiter, char annotate,
std::vector<std::string> *head_ptr, std::vector<std::string> *content_ptr,
const array<T> &in_vec, const array<Args>&... 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<std::string>(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<std::string> &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<std::string> &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<point3dc> &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<point3ds> &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<point3dc> &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<point3ds> &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<array<double>*> dat_val,
std::initializer_list<int> 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<array<double>*> dat_val,
std::initializer_list<int> 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<array<double>*> dat_val,
std::initializer_list<std::string> 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<std::vector<double>*> dat_val,
std::initializer_list<std::string> dat_name, char delimiter = ' ', int precision = GCTL_PRECISION);
}
#endif //_GCTL_TEXT_IO_H