388 lines
11 KiB
C++
388 lines
11 KiB
C++
/********************************************************
|
||
* ██████╗ ██████╗████████╗██╗
|
||
* ██╔════╝ ██╔════╝╚══██╔══╝██║
|
||
* ██║ ███╗██║ ██║ ██║
|
||
* ██║ ██║██║ ██║ ██║
|
||
* ╚██████╔╝╚██████╗ ██║ ███████╗
|
||
* ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
|
||
* 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_STR_H
|
||
#define _GCTL_STR_H
|
||
|
||
#include "exceptions.h"
|
||
|
||
#include <cmath>
|
||
#include <cstring>
|
||
#include <iostream>
|
||
#include <fstream>
|
||
#include <sstream>
|
||
#include <vector>
|
||
|
||
namespace gctl
|
||
{
|
||
template <typename ObjValType>
|
||
void type2ss(ObjValType in_val, std::stringstream &out_ss)
|
||
{
|
||
out_ss.clear();
|
||
out_ss << in_val;
|
||
return;
|
||
}
|
||
|
||
template <typename OutValType>
|
||
int str2type(std::string in_str, OutValType &out_val, char sep = ' ')
|
||
{
|
||
std::stringstream tmp_ss;
|
||
|
||
if (sep != ' ')
|
||
{
|
||
std::string new_str = in_str;
|
||
std::string old_sep;
|
||
old_sep = sep;
|
||
std::string new_sep = " ";
|
||
for(std::string::size_type pos(0); pos != std::string::npos; pos += new_sep.length())
|
||
{
|
||
if((pos = new_str.find(old_sep, pos)) != std::string::npos)
|
||
{
|
||
new_str.replace(pos,old_sep.length(), new_sep);
|
||
}
|
||
else break;
|
||
}
|
||
|
||
tmp_ss.clear();
|
||
tmp_ss.str(new_str);
|
||
}
|
||
else
|
||
{
|
||
tmp_ss.clear();
|
||
tmp_ss.str(in_str);
|
||
}
|
||
|
||
tmp_ss >> out_val;
|
||
|
||
if (tmp_ss.fail())
|
||
{
|
||
return -1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
template <typename OutValType>
|
||
void str2type_vector(const std::vector<std::string> &in_vec,
|
||
std::vector<OutValType> &out_data)
|
||
{
|
||
if (!out_data.empty()) out_data.clear();
|
||
out_data.resize(in_vec.size());
|
||
|
||
for (int i = 0; i < out_data.size(); i++)
|
||
{
|
||
if (str2type(in_vec[i], out_data[i]))
|
||
{
|
||
throw gctl::runtime_error("[gctl::str2type_vector] Failed to parse: " + in_vec[i]);
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
|
||
template <typename ValueType>
|
||
void type2str_vector(const std::vector<ValueType> &in_vec,
|
||
std::vector<std::string> &out_vec)
|
||
{
|
||
if (!out_vec.empty()) out_vec.clear();
|
||
out_vec.resize(in_vec.size());
|
||
|
||
for (size_t i = 0; i < in_vec.size(); i++)
|
||
{
|
||
out_vec[i] = std::to_string(in_vec[i]);
|
||
|
||
}
|
||
return;
|
||
}
|
||
|
||
template <typename ValueType>
|
||
void str2type_vector2d(const std::vector<std::vector<std::string> > &vec2d,
|
||
std::string order_str, std::vector<ValueType> &vec)
|
||
{
|
||
int idx;
|
||
std::string tmp_str;
|
||
std::stringstream tmp_ss(order_str);
|
||
std::getline(tmp_ss, tmp_str, ',');
|
||
|
||
tmp_ss.clear();
|
||
tmp_ss.str(tmp_str);
|
||
tmp_ss >> idx;
|
||
|
||
if (idx >= vec2d.size()) throw std::runtime_error("[gctl::str2type_vector2d] Invalid index.");
|
||
|
||
order_str = order_str.substr(order_str.find_first_of(',') + 1);
|
||
str2type_vector(vec2d[idx], vec);
|
||
return;
|
||
}
|
||
|
||
template <typename ValueType, typename... Args>
|
||
void str2type_vector2d(const std::vector<std::vector<std::string>> &vec2d,
|
||
std::string order_str, std::vector<ValueType> &vec, Args&... rest)
|
||
{
|
||
int idx;
|
||
std::string tmp_str;
|
||
std::stringstream tmp_ss(order_str);
|
||
std::getline(tmp_ss, tmp_str, ',');
|
||
|
||
tmp_ss.clear();
|
||
tmp_ss.str(tmp_str);
|
||
tmp_ss >> idx;
|
||
|
||
if (idx >= vec2d.size()) throw std::runtime_error("[gctl::str2type_vector2d] Invalid index.");
|
||
|
||
order_str = order_str.substr(order_str.find_first_of(',') + 1);
|
||
str2type_vector(vec2d[idx], vec);
|
||
|
||
str2type_vector2d(vec2d, order_str, rest...);
|
||
return;
|
||
}
|
||
|
||
template <typename ValueType>
|
||
void type2str_vector2d(std::vector<std::vector<ValueType> > &vec2d,
|
||
const std::vector<std::string> &vec)
|
||
{
|
||
std::vector<std::string> str_vec;
|
||
type2str_vector(vec, str_vec);
|
||
|
||
vec2d.push_back(str_vec);
|
||
return;
|
||
}
|
||
|
||
template <typename ValueType, typename... Args>
|
||
void type2str_vector2d(std::vector<std::vector<ValueType> > &vec2d,
|
||
const std::vector<std::string> &vec, Args&... rest)
|
||
{
|
||
std::vector<std::string> str_vec;
|
||
type2str_vector(vec, str_vec);
|
||
|
||
vec2d.push_back(str_vec);
|
||
|
||
type2str_vector2d(vec2d, rest...);
|
||
return;
|
||
}
|
||
|
||
/**
|
||
* @brief Parse a string argument into separated elements.
|
||
*
|
||
* @param[in] val_str The input value string
|
||
* @param[in] separator The separator
|
||
* @param[in] throw_err Throw out errors
|
||
* @param[in] fst_val The output values returned by quote
|
||
*
|
||
* @tparam ValueType Runtime value type
|
||
*
|
||
* @return Number of parsed strings
|
||
*/
|
||
template <typename ValueType>
|
||
int parse_string_to_value(std::string val_str, char separator, bool throw_err, ValueType &fst_val)
|
||
{
|
||
std::string tmp_str;
|
||
std::stringstream tmp_ss(val_str);
|
||
std::getline(tmp_ss, tmp_str, separator);
|
||
|
||
tmp_ss.clear();
|
||
tmp_ss.str(tmp_str);
|
||
tmp_ss >> fst_val;
|
||
|
||
if (throw_err && tmp_ss.fail())
|
||
{
|
||
throw std::runtime_error("Fail to parse the input string. From gctl::parse_string_to_value(...)");
|
||
}
|
||
else if (tmp_ss.fail())
|
||
{
|
||
return 0;
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
/**
|
||
* @brief Parse a string argument into separated elements.
|
||
*
|
||
* @param[in] val_str The input value string
|
||
* @param[in] separator The separator
|
||
* @param[in] throw_err Throw out errors
|
||
* @param[in] fst_val The output values returned by quote
|
||
*
|
||
* @tparam ValueType Runtime value type
|
||
* @tparam Args Runtime value types of the rest arguments
|
||
*
|
||
* @return Number of parsed strings
|
||
*/
|
||
template <typename ValueType, typename... Args>
|
||
int parse_string_to_value(std::string val_str, char separator, bool throw_err, ValueType &fst_val, Args&... rest)
|
||
{
|
||
std::string tmp_str;
|
||
std::stringstream tmp_ss(val_str);
|
||
std::getline(tmp_ss, tmp_str, separator);
|
||
|
||
tmp_ss.clear();
|
||
tmp_ss.str(tmp_str);
|
||
tmp_ss >> fst_val;
|
||
|
||
if (throw_err && tmp_ss.fail())
|
||
{
|
||
throw std::runtime_error("Fail to parse the input string. From gctl::parse_string_to_value(...)");
|
||
}
|
||
else if (tmp_ss.fail())
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
int position = val_str.find_first_of(separator);
|
||
|
||
if (position == std::string::npos) tmp_str = "";
|
||
else tmp_str = val_str.substr(position+1, val_str.length());
|
||
|
||
return parse_string_to_value(tmp_str, separator, throw_err, rest...) + 1;
|
||
}
|
||
|
||
/**
|
||
* @brief 替换字符串中的指定子串
|
||
*
|
||
* @param new_str 替换后的字符串
|
||
* @param old_str 需要操作的字符串
|
||
* @param old_value 需要被替换的字串
|
||
* @param new_value 替换的字串
|
||
*
|
||
* @return 替换的次数
|
||
*/
|
||
int replace_all(std::string& new_str, const std::string& old_str, const std::string& old_value,
|
||
const std::string& new_value);
|
||
|
||
/**
|
||
* @brief 在输入字符串末尾添加一段字符串,如果输入字符串的尾端与待添加的字符串一致则不添加并返回原字符串
|
||
*
|
||
* @param in_str 输入字符串
|
||
* @param patch_str 待匹配的字符串
|
||
* @return 输出字符串
|
||
*/
|
||
std::string patch_string(std::string in_str, std::string patch_str);
|
||
|
||
/**
|
||
* @brief 转换string对象为stringstream对象
|
||
*
|
||
* @param[in] in_str 输入的string字符串
|
||
* @param out_ss 引用返回的stringstreams对象
|
||
* @param[in] delimiter 分割string对象时的分隔符。如果不为空,
|
||
* 函数会将delimiter转换为空格
|
||
*/
|
||
void str2ss(std::string in_str, std::stringstream &out_ss, std::string delimiter = "");
|
||
|
||
/**
|
||
* @brief 转换string字符串为double类型的数值
|
||
*
|
||
* 这个函数的主要作用是检查输入字符串是否为nan或者inf等表示无效值的符号。有的编译器
|
||
* 可以在>>输入符中完成此检测,但为了函数功能的稳定,所以在此处自定了这个函数。这个函数
|
||
* 还可以将fortran输出文件中以D标注的科学数字转换为浮点类型
|
||
*
|
||
* @param[in] instr 输入字符串
|
||
*
|
||
* @return 返回的double类型的数值
|
||
*/
|
||
double str2double(std::string instr);
|
||
|
||
/**
|
||
* @brief 转换double类型数值为string类型字符串 标准库中有to_string函数,以后就不用这个了。
|
||
*
|
||
* @param[in] in_d 输入数值
|
||
*
|
||
* @return 输出字符串
|
||
*/
|
||
std::string double2str(double in_d);
|
||
|
||
/**
|
||
* @brief 返回一定长度的随机字符串
|
||
*
|
||
* @param[in] length 字符串的长度
|
||
* @param out 输出字符串
|
||
*/
|
||
void random_char(unsigned int length, char* out);
|
||
|
||
/**
|
||
* @brief 返回一定长度的随机字符串
|
||
*
|
||
* @param[in] length 字符串的长度
|
||
* @param out_str 输出字符串
|
||
*/
|
||
void random_str(unsigned int lenght, std::string &out_str);
|
||
|
||
/**
|
||
* @brief Parse a string argument into an element array
|
||
*
|
||
* @param[in] val_str The input value string
|
||
* @param out_vec The output array
|
||
* @param[in] separator The separator
|
||
*
|
||
* @tparam ValueType Runtime value type
|
||
*
|
||
* @return 0 for success, -1 for failure
|
||
*/
|
||
template <typename ValueType>
|
||
int parse_string_to_vector(std::string val_str, char separator, std::vector<ValueType> &out_vec)
|
||
{
|
||
val_str.erase(0, val_str.find_first_not_of(" \t"));
|
||
val_str.erase(val_str.find_last_not_of(" \t") + 1);
|
||
|
||
int pos;
|
||
bool bk = false;
|
||
ValueType val;
|
||
std::string l_str;
|
||
while (1)
|
||
{
|
||
pos = val_str.find(separator);
|
||
if (pos == val_str.npos)
|
||
{
|
||
l_str = val_str;
|
||
bk = true;
|
||
}
|
||
else
|
||
{
|
||
l_str = val_str.substr(0, pos);
|
||
val_str = val_str.substr(pos+1, val_str.length());
|
||
val_str.erase(0, val_str.find_first_not_of(" \t"));
|
||
}
|
||
|
||
// 如果输出也是字符串 就直接赋值即可(避免l_str中含有空格会出现bug)
|
||
if constexpr (std::is_same<ValueType, std::string>::value) val = l_str;
|
||
else str2type(l_str, val);
|
||
|
||
out_vec.push_back(val);
|
||
if (bk) break;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 解析字符串并返回以空格分割的字符串向量
|
||
*
|
||
* @note 双引号括起来的部分将解析为一个字符串
|
||
*
|
||
* @param in_str 输入字符串
|
||
* @param str_vec 输出字符串向量
|
||
*/
|
||
void parse_string_with_quotes(std::string in_str, std::vector<std::string> &str_vec);
|
||
};
|
||
|
||
#endif // _GCTL_STR_H
|