gctl/lib/io/text_io.h
2024-09-10 15:45:07 +08:00

1239 lines
31 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_;
// 注释行起始符 标记行起始符 分割符
char att_sym_, tag_sym_, delimiter_;
// 文件扩展名
std::string file_name_, file_ext_;
// 注释行 标记行
std::vector<std::string> 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 <typename T>
void read_text2vector(std::string filename, std::vector<T> &out_vec, char annotate = '#', unsigned int head_record = 0,
std::vector<std::string> *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 <typename T>
void read_text2array(std::string filename, array<T> &out_arr, char annotate = '#', unsigned int head_record = 0,
array<std::string> *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 <typename T>
void save_vector2text(std::string filename, const std::vector<T> &in_vec, char annotate = '#',
std::vector<std::string> *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 <typename T>
void save_array2text(std::string filename, const array<T> &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 <typename T>
void read_text2vector2d(std::string filename, std::vector<std::vector<T>> &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<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_)
{
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 <typename T>
void save_vector2d2text(std::string filename, const std::vector<std::vector<T>> &out_vec2d,
char delimiter = ' ', char annotate = '#', std::vector<std::string> *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 <typename T>
void save_matrix2text(std::string filename, const matrix<T> &out_arr2d,
char delimiter = ' ', char annotate = '#', std::vector<std::string> *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 <typename T>
void read_text2vectors(std::string filename, std::string order_str,
char delimiter, char annotate, int head_record, std::vector<T> &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 <typename T, typename... Args>
void read_text2vectors(std::string filename, std::string order_str, char delimiter,
char annotate, int head_record, 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, 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 <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 << content_ptr->at(i) << 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