gctl/lib/io/dsv_io.h
2024-12-16 09:31:46 +08:00

542 lines
13 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_IO2_H
#define _GCTL_TEXT_IO2_H
#include "../core.h"
#include "../utility.h"
#include "../geometry.h"
namespace gctl
{
struct cell_content
{
std::string str_;
template <typename T> T value()
{
// 如果输出也是字符串 就直接赋值即可避免l_str中含有空格会出现bug
if constexpr (std::is_same<T, std::string>::value) return str_;
else
{
T out;
str2type(str_, out);
return out;
}
}
template <typename T> void value(const T &in, int p = 6)
{
// 对于double类型 可以设置转换的有效数字位数(精度)
if constexpr (std::is_same<T, double>::value)
{
std::stringstream ss;
ss.precision(p);
ss << in;
ss >> str_;
}
else str_ = std::to_string(in);
return;
}
};
/**
* @brief 表格的头信息类型
*
*/
enum table_headtype_e
{
NoHead, // 没有表头
BothHead, // 同时有行与列表头
ColumnHead, // 只有列表头
RowHead, // 只有行表头
};
/**
* @brief 文本读写类
*
* 可以处理的文本数据应该符合下述要求:
* 1. 以'#'开始的行均为注释行,标识符可由用户指定;
* 2. 以'#!'开始的行均为标记行,标识符可由用户指定;
* 3. 文本开始可以包含n行头信息
* 4. 数据体为一个row*col大小的表格
* 5. 数据体可以包含一列行名称与列名称。
*
*/
class dsv_io
{
protected:
std::string file_;
table_headtype_e thead_;
// 头信息行数 表格行数 表格列数
int head_num_, row_num_, col_num_;
// 注释行起始符 标记行起始符 分割符
char att_sym_, tag_sym_, deli_sym_;
// 头信息行 注释行 标记行
std::vector<std::string> heads_, annotates_, tags_;
// 内容表格
std::vector<std::vector<cell_content> > table_;
public:
/**
* @brief Construct a new text content object
*
*/
dsv_io();
/**
* @brief Destroy the text content object
*
*/
~dsv_io();
/**
* @brief Construct a new text descriptor object and load text file
*
* @param filename 文件名
* @param file_exten 文件扩展名
*/
dsv_io(std::string filename, std::string file_exten = ".txt", table_headtype_e t = NoHead);
/**
* @brief 设置列分隔符
*
* @param deli_sym 分隔符
*/
void set_delimeter(char deli_sym){deli_sym_ = deli_sym;}
/**
* @brief 设置头信息行数
*
* @param num 行数
*/
void set_head_number(char num){head_num_ = num;}
/**
* @brief 设置注释行符号
*
* @param att_sym 注释符号
*/
void set_annotation_symbol(char att_sym){att_sym_ = att_sym;}
/**
* @brief 设置标记行符号
*
* @param tag_sym 标记符号
*/
void set_tag_symbol(char tag_sym){tag_sym_ = tag_sym;}
/**
* @brief 返回头信息行数
*
* @return 行数
*/
int head_number(){return head_num_;}
/**
* @brief 返回行数
*
* @return 行数
*/
int row_number(){return row_num_;}
/**
* @brief 返回列数
*
* @return 列数
*/
int col_number(){return col_num_;}
/**
* @brief 返回头信息
*
* @return 头信息
*/
const std::vector<std::string>& get_head_records(){return heads_;}
/**
* @brief 返回注释行
*
* @return 注释行
*/
const std::vector<std::string>& get_annotoations(){return annotates_;}
/**
* @brief 返回标记行
*
* @return 标记
*/
const std::vector<std::string>& get_tags(){return tags_;}
/**
* @brief 设置头信息
*
* @param heads 头信息
*/
void set_head_records(const std::vector<std::string> &heads);
/**
* @brief 设置注释
*
* @param att 注释
*/
void set_annotoations(const std::vector<std::string> &att);
/**
* @brief 设置标记
*
* @param tags 标记
*/
void set_tags(const std::vector<std::string> &tags);
/**
* @brief 清理字符串向量对象
*
*/
void clear();
/**
* @brief 读入文本文件
*
* @param filename 文件名
* @param file_exten 文件扩展名
*/
void load_text(std::string filename, std::string file_exten = ".txt", table_headtype_e t = NoHead);
/**
* @brief 读入CSV文件
*
* @param filename 文件名
*/
void load_csv(std::string filename, table_headtype_e t = ColumnHead);
/**
* @brief 将内容写入文件
*
* @param filename 文件名
* @param file_exten 文件扩展名
*/
void save_text(std::string filename, std::string file_exten = ".txt");
/**
* @brief 将内容写入CSV文件
*
* @param filename 文件名(无后缀)
*/
void save_csv(std::string filename);
/**
* @brief 初始化表格
*
* @param row 行数
* @param col 列数
*/
void init_table(int row, int col, table_headtype_e t = ColumnHead);
/**
* @brief 返回表格信息
*
*/
void info();
/**
* @brief 填充列
*
* @tparam T 数据类型
* @param idx 列索引
* @param data 列数据
*/
template <typename T> void fill_column(int idx, const array<T> &data, int p = 6);
/**
* @brief 填充列
*
* @tparam T 数据类型
* @param name 列名称
* @param data 列数据
*/
template <typename T> void fill_column(std::string name, const array<T> &data, int p = 6);
/**
* @brief 填充行
*
* @tparam T 数据类型
* @param idx 行索引
* @param data 行数据
*/
template <typename T> void fill_row(int idx, const array<T> &data, int p = 6);
/**
* @brief 填充行
*
* @tparam T 数据类型
* @param name 行名称
* @param data 行数据
*/
template <typename T> void fill_row(std::string name, const array<T> &data, int p = 6);
/**
* @brief 获取列数据
*
* @tparam T 数据类型
* @param idx 列索引
* @param data 列数据
*/
template <typename T> void get_column(int idx, array<T> &data);
/**
* @brief 获取列数据
*
* @tparam T 数据类型
* @param name 列名称
* @param data 列数据
*/
template <typename T> void get_column(std::string name, array<T> &data);
/**
* @brief 获取行数据
*
* @tparam T 数据类型
* @param idx 行索引
* @param data 行数据
*/
template <typename T> void get_row(int idx, array<T> &data);
/**
* @brief 获取行数据
*
* @tparam T 数据类型
* @param name 行名称
* @param data 行数据
*/
template <typename T> void get_row(std::string name, array<T> &data);
/**
* @brief 获取表格单元数据
*
* @tparam T 数据类型
* @param r 行号
* @param c 列号
* @return T 单元数据
*/
template <typename T> T cell(int r, int c){return table_[r][c].value<T>();}
/**
* @brief 填充表格单元数据
*
* @tparam T 数据类型
* @param r 行号
* @param c 列号
* @param d 数据
*/
template <typename T> void cell(int r, int c, T d, int p = 6){table_[r][c].value(d, p); return;}
};
template <typename T>
void dsv_io::fill_column(int idx, const array<T> &data, int p)
{
if (idx >= col_num_)
{
throw std::runtime_error("[gctl::dsv_io::fill_column] Invalid column index.");
}
int st = 0;
if (thead_ == ColumnHead || thead_ == BothHead) st = 1;
for (size_t i = st; i < std::min(row_num_, data.size()); i++)
{
table_[i][idx].value(data[i - st], p);
}
return;
}
template <typename T>
void dsv_io::fill_column(std::string name, const array<T> &data, int p)
{
if (thead_ != ColumnHead && thead_ != BothHead)
{
throw std::runtime_error("[gctl::dsv_io::fill_column] The table is initialized with no column names.");
}
for (size_t i = 0; i < col_num_; i++)
{
if (table_[0][i].str_ == name)
{
fill_column(i, data, p);
return;
}
}
throw std::runtime_error("[gctl::dsv_io::fill_column] No column found by the input name.");
return;
}
template <typename T>
void dsv_io::fill_row(int idx, const array<T> &data, int p)
{
if (idx >= row_num_)
{
throw std::runtime_error("[gctl::dsv_io::fill_row] Invalid row index.");
}
int st = 0;
if (thead_ == RowHead || thead_ == BothHead) st = 1;
for (size_t i = st; i < std::min(col_num_, data.size()); i++)
{
table_[idx][i].value(data[i - st], p);
}
return;
}
template <typename T>
void dsv_io::fill_row(std::string name, const array<T> &data, int p)
{
if (thead_ != RowHead && thead_ != BothHead)
{
throw std::runtime_error("[gctl::dsv_io::fill_row] The table is initialized with no row names.");
}
for (size_t i = 0; i < row_num_; i++)
{
if (table_[i][0].str_ == name)
{
fill_row(i, data, p);
return;
}
}
throw std::runtime_error("[gctl::dsv_io::fill_row] No row found by the input name.");
return;
}
template <typename T>
void dsv_io::get_column(int idx, array<T> &data)
{
if (idx >= col_num_)
{
throw std::runtime_error("[gctl::dsv_io::get_column] Invalid column index.");
}
int st = 0;
if (thead_ == ColumnHead || thead_ == BothHead) st = 1;
data.resize(row_num_ - st);
for (size_t i = st; i < row_num_; i++)
{
data[i - st] = table_[i][idx].value<T>();
}
return;
}
template <typename T>
void dsv_io::get_column(std::string name, array<T> &data)
{
if (thead_ != ColumnHead && thead_ != BothHead)
{
throw std::runtime_error("[gctl::dsv_io::get_column] The table is initialized with no column names.");
}
for (size_t i = 0; i < col_num_; i++)
{
if (table_[0][i].str_ == name)
{
get_column(i, data);
return;
}
}
throw std::runtime_error("[gctl::dsv_io::get_column] No column found by the input name.");
return;
}
template <typename T>
void dsv_io::get_row(int idx, array<T> &data)
{
if (idx >= row_num_)
{
throw std::runtime_error("[gctl::dsv_io::get_row] Invalid row index.");
}
int st = 0;
if (thead_ == RowHead || thead_ == BothHead) st = 1;
data.resize(col_num_ - st);
for (size_t i = st; i < col_num_; i++)
{
data[i - st] = table_[idx][i].value<T>();
}
return;
}
template <typename T>
void dsv_io::get_row(std::string name, array<T> &data)
{
if (thead_ != RowHead && thead_ != BothHead)
{
throw std::runtime_error("[gctl::dsv_io::get_row] The table is initialized with no row names.");
}
for (size_t i = 0; i < row_num_; i++)
{
if (table_[i][0].str_ == name)
{
get_row(i, data);
return;
}
}
throw std::runtime_error("[gctl::dsv_io::get_row] No row found by the input name.");
return;
}
class geodsv_io : public dsv_io
{
public:
geodsv_io();
~geodsv_io();
/**
* @brief Construct a new text descriptor object and load text file
*
* @param filename 文件名
* @param file_exten 文件扩展名
*/
geodsv_io(std::string filename, std::string file_exten = ".txt", table_headtype_e t = NoHead);
void fill_column_point2dc(int xid, int yid, const array<point2dc> &data, int p = 6);
void fill_column_point3dc(int xid, int yid, int zid, const array<point3dc> &data, int p = 6);
void get_column_point2dc(int xid, int yid, array<point2dc> &data);
void get_column_point3dc(int xid, int yid, int zid, array<point3dc> &data);
};
}
#endif //_GCTL_TEXT_IO2_H