I need to write a function that searches through a string and checks to see what data type is being used. For example, I need to figure out if the string contains a float, a char, or multiple ints. Then my function needs to pass that data to an overloaded function which will do something else with it.
Basically I'm looking for what function I should be using to search through the string and an example of how to use it would be nice.
CodePudding user response:
To answer a question in the title:
Yes, there IS a way to search a string.
To look for any single character (for example, decimal point), use find.
To look for any one of the list of characters (for example, digits) use find_first_of.
CodePudding user response:
And to answer the question body, if you wish to know what "type" of thing a string contains you have two options:
- try to convert it to that type (using istringstream and operator >>)
- use a regular expression (or other pattern matching algorithm)
As already noted to you, this takes the effort on your part to clearly specify what uniquely constitutes each "type" of thing you wish to identify.
For example. In C , 1 is an int, 1.0 is a double, etc.
CodePudding user response:
you could do a rough check, find_first_not_of("01234567890.") to see if it looks like a number or not. Then do lexical_cast (or stringstream <<) and see if it succeeds. If not then assume string.
Probably should do 0123456789 (not .) to see if its an integer, then if the first_not_of is "." do a lexicalcast as float else treat it as character string
probably sniff at first char to see if '-'
CodePudding user response:
It seems you want a parser that infers the type of the expression. This can be accomplished by trying different conversions and see if they succeed. Whenever they fail, jump to the next conversion. So a 1 would be a std::uint8_t, but a -1 would be a std::int8_t, a 1.0 would be a float while a 1e 40 would be a double and so forth.
Fortunately C 17 added a function that does close to what you want: std::from_chars.
#include <charconv>
#include <string>
#include <variant>
#include <optional>
#include <cstdint>
namespace {
using Value = std::variant<
long double, double, float,
std::uint64_t, std::int64_t,
std::uint32_t, std::int32_t,
std::uint16_t, std::int16_t,
std::uint8_t, std::int8_t,
std::string // last resort if nothing works
>;
template <typename T>
std::optional<T> parse_as(char const* const begin, char const* const end) {
if (begin == end) return std::nullopt;
T value{};
auto const [ptr, ec] = std::from_chars(begin,end,value);
if (ec == std::errc::result_out_of_range || ec == std::errc::invalid_argument || ptr != end) {
return std::nullopt;
}
return value;
}
Value parse(std::string const& str) {
auto const b = str.data();
auto const e = str.data() str.size();
if (auto const r = parse_as<std::uint8_t>(b,e)) return *r;
if (auto const r = parse_as<std::int8_t>(b,e)) return *r;
if (auto const r = parse_as<std::uint16_t>(b,e)) return *r;
if (auto const r = parse_as<std::int16_t>(b,e)) return *r;
if (auto const r = parse_as<std::uint32_t>(b,e)) return *r;
if (auto const r = parse_as<std::int32_t>(b,e)) return *r;
if (auto const r = parse_as<std::uint64_t>(b,e)) return *r;
if (auto const r = parse_as<std::int64_t>(b,e)) return *r;
if (auto const r = parse_as<float>(b,e)) return *r;
if (auto const r = parse_as<double>(b,e)) return *r;
if (auto const r = parse_as<long double>(b,e)) return *r;
return str;
}
}
Here is a small test that shows how this works:
#include <iostream>
// helper type
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
void show(std::string const& str) {
std::visit(overloaded {
[](std::uint8_t const arg) {
std::cout << int{arg} << "\tsize: " << sizeof(arg) << "\n";
},
[](std::int8_t const arg) {
std::cout << int{arg} << "\tsize: " << sizeof(arg) << "\n";
},
[](auto const arg) {
std::cout << arg << "\tsize: " << sizeof(arg) << "\n";
}
}, parse(str));
}
int main() {
show("hello");
show("64");
show("7000");
show("-7000");
show("-127");
show("1.0");
show("1e 40");
show("1e 400");
}
This will correctly print:
hello size: 32
64 size: 1
7000 size: 2
-7000 size: 2
-127 size: 1
1 size: 4
1e 40 size: 8
1e 400 size: 16
Here is a live demo.
