/********************************************************
* ██████╗ ██████╗████████╗██╗
* ██╔════╝ ██╔════╝╚══██╔══╝██║
* ██║ ███╗██║ ██║ ██║
* ██║ ██║██║ ██║ ██║
* ╚██████╔╝╚██████╗ ██║ ███████╗
* ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
* 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_;
// 注释行起始符 标记行起始符 分割符
char att_sym_, tag_sym_, delimiter_;
// 文件扩展名
std::string file_name_, file_ext_;
// 注释行 标记行
std::vector head_strs_, annotates_, tags_;
text_descriptor();
/**
* @brief Construct a new text descriptor object
*
* @param filename 文件名
* @param file_exten 文件扩展名
* @param att_sym 注释行起始符
* @param tag_sym 标记行起始符
* @param deli 分割符
*/
text_descriptor(std::string filename, std::string file_exten = ".txt", char att_sym = '#', char tag_sym = '>', char deli = ' ', int h_num = 0);
~text_descriptor();
/**
* @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", char att_sym = '#', char tag_sym = '>', char deli = ' ', int h_num = 0);
void clear();
};
/**
* @brief 从文本文件读入行到一维向量
*
* @note 文件中的每一行为向量中的一个元素,对应的元素类型需支持>>操作符(一般通过操作符重载实现)
*
* @param[in] filename 文件名
* @param[in] file_ext 文件后缀名(默认包括txt dat xyz csv)
* @param out_vec 返回的一维向量
* @param[in] annotate 注释行的标记
* @param[in] head_record 头信息行数
* @param head_ptr 保存头信息的一维字符串向量的指针
*
* @tparam T 模版向量类型
*/
template
void read_text2vector(std::string filename, std::vector &out_vec, char annotate = '#', unsigned int head_record = 0,
std::vector *head_ptr = nullptr, std::string file_ext = ".txt,.dat,.xyz,.csv")
{
std::string tmp_line;
std::stringstream tmp_ss;
std::ifstream infile;
open_matched_infile(infile, filename, file_ext);
// clear cleanup old table
if (!out_vec.empty()) destroy_vector(out_vec);
if (head_ptr != nullptr && !head_ptr->empty()) destroy_vector(*head_ptr);
if (head_record > 0)
{
for (int i = 0; i < head_record; i++)
{
getline(infile, tmp_line);
if (head_ptr != nullptr) head_ptr->push_back(tmp_line);
}
}
T tmp_d;
while (std::getline(infile, tmp_line))
{
if (tmp_line[0] == annotate) continue;
else
{
tmp_ss.clear();
tmp_ss.str(tmp_line);
tmp_ss >> tmp_d;
if (tmp_ss.fail())
{
throw runtime_error("Fail to parse the element: "+tmp_line+". From read_text2vector(...)");
}
out_vec.push_back(tmp_d);
}
}
infile.close();
return;
}
template
void read_text2array(std::string filename, array &out_arr, char annotate = '#', unsigned int head_record = 0,
array *head_ptr = nullptr, std::string file_ext = ".txt,.dat,.xyz,.csv")
{
std::string tmp_line;
std::stringstream tmp_ss;
std::ifstream infile;
open_matched_infile(infile, filename, file_ext);
// clear cleanup old table
if (!out_arr.empty()) out_arr.clear();
if (head_ptr != nullptr && !head_ptr->empty()) head_ptr->clear();
if (head_ptr != nullptr && head_record > 0) head_ptr->resize(head_record);
int line_count = 0, annotate_count = 0;
while (std::getline(infile, tmp_line))
{
line_count++;
if (tmp_line[0] == annotate) annotate_count++;
}
// reset the file pointer
infile.clear(); infile.seekg(0);
if (line_count == 0)
{
throw length_error("File: " + filename + " is empty. From read_text2array(...)");
}
int arr_size = line_count - annotate_count - head_record;
if (arr_size <= 0)
{
throw length_error("No valid entrance in the file: " + filename + " From read_text2array(...)");
}
out_arr.resize(arr_size);
int count = 0;
if (head_record > 0)
{
while (count < head_record)
{
std::getline(infile, tmp_line);
if (tmp_line[0] == annotate) continue;
else
{
if (head_ptr != nullptr) head_ptr->at(count) = tmp_line;
count++;
}
}
}
T tmp_d;
count = 0;
while (std::getline(infile, tmp_line))
{
if (tmp_line[0] == annotate) continue;
else
{
tmp_ss.clear();
tmp_ss.str(tmp_line);
tmp_ss >> tmp_d;
if (tmp_ss.fail())
{
throw runtime_error("Fail to parse the element: "+tmp_line+". From read_text2array(...)");
}
out_arr[count] = tmp_d;
count++;
}
}
infile.close();
return;
}
/**
* @brief 保存一维向量到文本文件
*
* @note 向量中的每个元素保存为一行,对应的元素类型需支持<<操作符(一般通过操作符重载实现)
*
* @param[in] filename 保存文件名
* @param[in] file_ext 保存文件的后缀
* @param[in] in_vec 待输出的向量
* @param[in] annotate 注释行的标记
* @param[in] head_info 头信息向量的指针
* @param[in] precision 设置输出的数据精度,此值为正时将在<<操作符后附加setprecision(precision)代码段
*
* @tparam T 模版向量类型
*/
template
void save_vector2text(std::string filename, const std::vector &in_vec, char annotate = '#',
std::vector *head_ptr = nullptr, int precision = -1, std::string file_ext = ".txt,.dat,.xyz,.csv")
{
std::ofstream outfile;
open_matched_outfile(outfile, filename, file_ext);
if (in_vec.empty())
{
GCTL_ShowWhatError("The input vector is empty. From save_vector2text(...)", GCTL_WARNING_ERROR, 0, 0, 0);
}
if (head_ptr != nullptr)
{
for (int i = 0; i < head_ptr->size(); ++i)
{
outfile << annotate << " " << head_ptr->at(i) << std::endl;
}
}
if (precision > 0)
{
for (int i = 0; i < in_vec.size(); i++)
{
outfile << std::setprecision(precision) << in_vec[i] << std::endl;
}
outfile.close();
return;
}
for (int i = 0; i < in_vec.size(); i++)
{
outfile << in_vec[i] << std::endl;
}
outfile.close();
return;
}
/**
* @brief 保存一维数组到文本文件
*
* @note 数组的每个元素保存为一行,对应的元素类型需支持<<操作符(一般通过操作符重载实现)
*
* @param[in] filename 保存文件名
* @param[in] file_ext 保存文件的后缀
* @param[in] in_arr 待输出的向量
* @param[in] annotate 注释行的标记
* @param[in] head_info 头信息向量的指针
* @param[in] precision 设置输出的数据精度,此值为正时将在<<操作符后附加setprecision(precision)代码段
*
* @tparam T 模版向量类型
*/
template
void save_array2text(std::string filename, const array &in_arr, const text_descriptor &desc,
int precision = -1, std::string file_ext = ".txt,.dat,.xyz,.csv")
{
std::ofstream outfile;
open_matched_outfile(outfile, filename, file_ext);
if (in_arr.empty())
{
GCTL_ShowWhatError("The input array is empty. From save_vector2text(...)", GCTL_WARNING_ERROR, 0, 0, 0);
}
for (int i = 0; i < desc.annotates_.size(); ++i)
{
outfile << desc.annotates_[i] << std::endl;
}
if (precision > 0)
{
for (int i = 0; i < in_arr.size(); i++)
{
outfile << std::fixed << std::setprecision(precision) << in_arr[i] << std::endl;
}
outfile.close();
return;
}
for (int i = 0; i < in_arr.size(); i++)
{
outfile << in_arr[i] << std::endl;
}
outfile.close();
return;
}
template
void read_text2vector2d(std::string filename, std::vector> &out_vec2d, text_descriptor &desc, std::string file_ext = ".txt,.dat,.xyz,.csv,.tab")
{
std::ifstream infile;
open_matched_infile(infile, filename, 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_)
{
desc.annotates_.push_back(tmp_line);
}
else if (tmp_line[0] == desc.tag_sym_)
{
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(std::string filename, const std::vector> &out_vec2d,
char delimiter = ' ', char annotate = '#', std::vector *head_ptr = nullptr,
matrix_order_e order_type = RowMajor, int precision = -1, std::string file_ext = ".txt,.dat,.xyz,.csv")
{
std::ofstream outfile;
open_matched_outfile(outfile, filename, file_ext);
if (out_vec2d.empty())
{
GCTL_ShowWhatError("The input vector is empty. From save_vector2d2text(...)", GCTL_WARNING_ERROR, 0, 0, 0);
}
if (head_ptr != nullptr)
{
for (int i = 0; i < head_ptr->size(); i++)
{
outfile << annotate << " " << head_ptr->at(i) << std::endl;
}
}
if (order_type == RowMajor)
{
if (precision > 0)
{
for (int i = 0; i < out_vec2d.size(); i++)
{
outfile << std::setprecision(precision) << out_vec2d[i][0];
for (int j = 1; j < out_vec2d.at(i).size(); j++)
{
outfile << std::setprecision(precision) << delimiter << out_vec2d[i][j];
}
outfile << std::endl;
}
outfile.close();
return;
}
for (int i = 0; i < out_vec2d.size(); i++)
{
outfile << out_vec2d[i][0];
for (int j = 1; j < out_vec2d.at(i).size(); j++)
{
outfile << delimiter << out_vec2d[i][j];
}
outfile << std::endl;
}
outfile.close();
return;
}
if (precision > 0)
{
for (int i = 0; i < out_vec2d[0].size(); i++)
{
outfile << std::setprecision(precision) << out_vec2d[0][i];
for (int j = 1; j < out_vec2d.size(); j++)
{
outfile << std::setprecision(precision) << delimiter << out_vec2d[j][i];
}
outfile << std::endl;
}
outfile.close();
return;
}
for (int i = 0; i < out_vec2d[0].size(); i++)
{
outfile << out_vec2d[0][i];
for (int j = 1; j < out_vec2d.size(); j++)
{
outfile << delimiter << out_vec2d[j][i];
}
outfile << std::endl;
}
outfile.close();
return;
}
template
void save_matrix2text(std::string filename, const matrix &out_arr2d,
char delimiter = ' ', char annotate = '#', std::vector *head_ptr = nullptr,
matrix_order_e order_type = RowMajor, int precision = -1, std::string file_ext = ".txt,.dat,.xyz,.csv")
{
std::ofstream outfile;
open_matched_outfile(outfile, filename, file_ext);
if (out_arr2d.empty())
{
GCTL_ShowWhatError("The input array is empty. From save_matrix2text(...)", GCTL_WARNING_ERROR, 0, 0, 0);
}
if (head_ptr != nullptr)
{
for (int i = 0; i < head_ptr->size(); i++)
{
outfile << annotate << " " << head_ptr->at(i) << std::endl;
}
}
if (order_type == RowMajor)
{
if (precision > 0)
{
for (int i = 0; i < out_arr2d.row_size(); i++)
{
outfile << std::setprecision(precision) << out_arr2d[i][0];
for (int j = 1; j < out_arr2d.col_size(); j++)
{
outfile << std::setprecision(precision) << delimiter << out_arr2d.at(i, j);
}
outfile << std::endl;
}
outfile.close();
return;
}
for (int i = 0; i < out_arr2d.row_size(); i++)
{
outfile << out_arr2d[i][0];
for (int j = 1; j < out_arr2d.col_size(); j++)
{
outfile << delimiter << out_arr2d.at(i, j);
}
outfile << std::endl;
}
outfile.close();
return;
}
if (precision > 0)
{
for (int i = 0; i < out_arr2d.col_size(); i++)
{
outfile << std::setprecision(precision) << out_arr2d[0][i];
for (int j = 1; j < out_arr2d.row_size(); j++)
{
outfile << std::setprecision(precision) << delimiter << out_arr2d.at(j, i);
}
outfile << std::endl;
}
outfile.close();
return;
}
for (int i = 0; i < out_arr2d.col_size(); i++)
{
outfile << out_arr2d[0][i];
for (int j = 1; j < out_arr2d.row_size(); j++)
{
outfile << delimiter << out_arr2d.at(j, i);
}
outfile << std::endl;
}
outfile.close();
return;
}
template
void read_text2vectors(std::string filename, std::string order_str,
char delimiter, char annotate, int head_record, std::vector &out_vec)
{
std::string tmp_line, tmp_str, tmp_str2;
std::stringstream tmp_ss;
std::ifstream infile;
open_infile(infile, filename);
// clear cleanup old table
if (!out_vec.empty()) destroy_vector(out_vec);
tmp_ss.clear();
tmp_ss.str(order_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("Invalid column index. From read_text2vectors(...)");
}
if (head_record > 0)
{
for (int i = 0; i < head_record; i++)
{
getline(infile, tmp_line);
}
}
T tmp_d;
if (delimiter != ' ')
{
while (std::getline(infile, tmp_line))
{
if (tmp_line[0] == annotate) continue;
else
{
// replace all delimiters to spaces
tmp_str2 = 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("Fail to parse the line: "+tmp_line+". From read_text2vectors(...)");
}
out_vec.push_back(tmp_d);
}
}
}
else
{
while (std::getline(infile, tmp_line))
{
if (tmp_line[0] == annotate) continue;
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("Fail to parse the line: "+tmp_line+". From read_text2vectors(...)");
}
out_vec.push_back(tmp_d);
}
}
}
infile.close();
return;
}
template
void read_text2vectors(std::string filename, std::string order_str, char delimiter,
char annotate, int head_record, 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, filename);
// clear cleanup old table
if (!out_vec.empty()) destroy_vector(out_vec);
tmp_ss.clear();
tmp_ss.str(order_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("Invalid column index. From read_text2vectors(...)");
}
int position = order_str.find_first_of(',');
std::string tmp_order = order_str.substr(position+1, order_str.length());
if (head_record > 0)
{
for (int i = 0; i < head_record; i++)
{
getline(infile, tmp_line);
}
}
T tmp_d;
if (delimiter != ' ')
{
while (std::getline(infile, tmp_line))
{
if (tmp_line[0] == annotate) continue;
else
{
// replace all delimiters to spaces
tmp_str2 = 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("Fail to parse the line: "+tmp_line+". From read_text2vectors(...)");
}
out_vec.push_back(tmp_d);
}
}
}
else
{
while (std::getline(infile, tmp_line))
{
if (tmp_line[0] == annotate) continue;
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("Fail to parse the line: "+tmp_line+". From read_text2vectors(...)");
}
out_vec.push_back(tmp_d);
}
}
}
infile.close();
read_text2vectors(filename, tmp_order, delimiter, annotate, head_record, 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 << content_ptr->at(i) << 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