Convert string with thousands (and decimal) separator into double - c++

User can enter double into textbox. Number might contain thousands separators. I want to validate user input, before inserting entered number into database.
Is there a C++ function that can convert such input (1,555.99) into double? If there is, can it signal error if input is invalid (I do not want to end up with function similar to atof)?
Something like strtod, but must accept input with thousands separators.

Convert the input to double using a stream that's been imbued with a locale that accepts thousand separators.
#include <locale>
#include <iostream>
int main() {
double d;
std::cin.imbue(std::locale(""));
std::cin >> d;
std::cout << d;
}
Here I've used the un-named locale, which retrieves locale information from the environment (e.g., from the OS) and sets an appropriate locale (e.g., in my case it's set to something like en_US, which supports commas as thousands separators, so:
Input: 1,234.5
Output: 1234.5
Of course, I could also imbue std::cout with some locale that (for example) uses a different thousands separator, and get output tailored for that locale (but in this case I've used the default "C" locale, which doesn't use thousands separators, just to make the numeric nature of the value obvious).
When you need to do this with something that's already "in" your program as a string, you can use an std::stringstream to do the conversion:
std::string input = "1,234,567.89";
std::istringstream buffer(input);
buffer.imbue(std::locale(""));
double d;
buffer >> d;

A C solution would be to use setlocale & sscanf:
const char *oldL = setlocale(LC_NUMERIC, "de_DE.UTF-8");
double d1 = 1000.43, d2 = 0;
sscanf("1.000,43", "%'lf", &d2);
if ( std::abs(d1-d2) < 0.01 )
printf("OK \n");
else
printf("something is wrong! \n");
setlocale(LC_NUMERIC, oldL);

Related

Is it possible to format number with thousands separator using fmt?

Is it possible to format number with thousands separator using fmt?
e.g. something like this:
int count = 10000;
fmt::print("{:10}\n", count);
update
I am researching fmt, so I am looking for solution that works with fmt library only, without modify locale in any way.
I found the answer online in Russian forum:
int count = 10000;
fmt::print("{:10L}\n", count);
This prints:
10,000
The thousands separator is locale depended and if you want to change it to something else, only then you need to "tinker" with locale classes.
According to the fmt API reference:
Use the 'L' format specifier to insert the appropriate number separator characters from the locale.
Note that all formatting is locale-independent by default.
#include <fmt/core.h>
#include <locale>
int main() {
std::locale::global(std::locale("es_CO.UTF-8"));
auto s = fmt::format("{:L}", 1'000'000); // s == "1.000.000"
fmt::print("{}\n", s); // "1.000.000"
return 0;
}

Cast a string from Glib::ustring to double - gtkm 2

I am developing an c++ app in gtkmm 2
I have a problem to cast the string from an entryfield to a double (or int).
I get the following compilation error
cannot convert from Glib::ustring to double
The entryfield
interestrate.set_max_length(50);
interestrate.set_text(interestrate.get_text() );
interestrate.select_region(0, interestrate.get_text_length());
m_box1.pack_start(interestrate);
interestrate.show();
the button
m_button3.signal_clicked().connect(sigc::bind<-1, Glib::ustring>(
sigc::mem_fun(*this, &HelloWorld::on_button_clicked), "OK"));
m_box1.pack_start(m_button3);
m_button3.show();
and the eventhandler
void HelloWorld::on_button_clicked(Glib::ustring data)
{
std::cout << "interestrate: " << interestrate.get_text() << std::endl;
}
so i want to get a double of the returnvalue from
interestrate.get_text()
I didnt beleive it could be so easy
std::string s = interestrate.get_text();
double d = atof(s.c_str());
Your suggestion would work for valid C locale input.
If you want to deal with bad number formats and locale considerations you have to do a little bit more; atof returns 0 on error, but 0 may be a valid input, and here in Germany users would perhaps enter a comma as the decimal point.
I would think (from reading the glib docs and this answer: How can I convert string to double in C++?), that you should get the proper localized std::string first via Glib::locale_from_utf8() and then create a stringstream from that and read your double out of that. The stream gives you error information and the conversion/operator>>() will deal with locale issues if you have "imbued" a locale.

C++ fstream - problems reading only certain variable types

I am using fstream to read a notepad file containing numerical data. I am using dynamic memory allocation and the data is type float.
However there is rouge data in form of characters in my file - how would I write code that searches for and ignores the characters in the file, and only reads in the numbers?
I am assuming I will need to use either ignore or peek?
fstream myfile("data1");
myfile.ignore ();
or myfile.peek ();
But am a bit unsure. Any help is appreciated!
If it has always this format, the words and numbers are separated by whitespace, you can simply read it one string at a time and let a std::istringstream do the parsing. When this fails, you know it is not a number
std::string word;
while (myfile >> word) {
std::istringstream is(word);
double d;
if (is >> d) {
// found a number
std::cout << d << '\n';
} else {
// something's wrong
std::cerr << word << '\n';
}
}
Update:
Due to popular demand: a stringstream works like any other stream (std::cin, std::cout or std::fstream). The main difference is that a stringstream operates on strings. This means input comes from a string instead of a file or standard input, or output goes to a string, much like it goes to standard output or a file.
Parsing input is like this typically requires that you extract the tokens into a string and
test the content of your string against your parsing requirements. For example, when you extract into the string, you can then run a function which inserts it into a std::stringstream, then extract into the data type you're testing against, and see if it succeeds.
Another option is to check if the string is not a certain string, and convert back to the desired data type if so:
while (f >> str)
{
if (f != "badInput")
{
// convert to double and add to array
}
}
Fortunately you can use the Boost.Regex facilities to avoid having to do most of the work yourself. Here's an example similar to yours:
#include <boost/regex.hpp>
int main()
{
std::fstream f("test.txt");
std::string token;
boost::regex floatingPoint("((\\+|-)?[0-9]+)?(\\.)?([0-9]+)");
while (f >> token)
{
if (boost::regex_match(token, floatingPoint))
{
// convert to double using lexical_cast<> and add to array
}
}
Thanks for the help everybody - But all this seems a bit advanced for someone of my poor capability! We have been suggested to use the following - but am unsure how you would do this to distinguish between words and numbers:
fstream myfile("data1");
myfile.eof ();
myfile.good ();
myfile.fail ();
myfile.clear ();
myfile.ignore ();
myfile.close ();
myfile.peek ();

How to parse quotation marks and comma in c++ [duplicate]

This question already has answers here:
How can I read and parse CSV files in C++?
(39 answers)
Closed 8 months ago.
I have a huge file to parse. Previously, it was separated by either space or comma and I used sscanf(string, "%lf %lf ", &aa, &bb); to get the data into my program.
But now the data format is changed to "122635.670399999","209705.752799999", with both comma and quotation marks. And I have no idea how to deal with it.
Actually, my previous code was found online and I had a really hard time finding proper documentation for this kind of problem. It will be great if you can recommend some to me.
Rather than read a string, then remove the commas and quotes from the strings, and finally convert the data to numbers, I'd probably create a locale object that classifies commas and quotes as white space, imbue the stream with that locale, and read the numbers without further adieu.
// here's our ctype facet:
class my_ctype : public std::ctype<char> {
public:
mask const *get_table() {
static std::vector<std::ctype<char>::mask>
table(classic_table(), classic_table()+table_size);
// tell it to classify quotes and commas as "space":
table['"'] = (mask)space;
table[','] = (mask)space;
return &table[0];
}
my_ctype(size_t refs=0) : std::ctype<char>(get_table(), false, refs) { }
};
Using that, we can read the data something like this:
int main() {
// Test input from question:
std::string input("\"122635.670399999\",\"209705.752799999\"");
// Open the "file" of the input (from the string, for test purposes).
std::istringstream infile(input);
// Tell the stream to use the locale we defined above:
infile.imbue(std::locale(std::locale(), new my_ctype));
// Read the numbers into a vector of doubles:
std:vector<double> numbers{std::istream_iterator<double>(infile),
std::istream_iterator<double>()};
// Print out the sum of the numbers to show we read them:
std::cout << std::accumulate(numbers.begin(), numbers.end(), 0.0);
}
Note that once we've imbued the stream with a locale using our ctype facet, we can just read numbers as if the commas and quotes didn't exist at all. Since the ctype facet classifies them as white-space, they're completely ignored beyond acting as separators between other stuff.
I'm pointing this out primarily to make clear that there's no magic in any of the processing after that. There's nothing special about using istream_iterator instead of (for example) double value; infile >> value; if you prefer to do that. You can read the numbers any of the ways you'd normally read numbers that were separated by white space -- because as far as the stream cares, that's exactly what you have.
if you have got comma separated data in strings then just remove " from string like :
let say string is str1
str1.erase(std::remove(str1.begin(), str1.end(), '"'), str1.end());
this will erase all occurrences of "
//Use below code to convert string into float
float f1;
std::stringstream ss;
ss<<str1;
ss>>f1;

testing for double in visual c++

I am designing a gui in visual c++ and there is a textbox where user inputs values so a calculation can be performed. How do I validate the input to ensure it can be cast to a double value?
In any C++ environment where you have a std::string field and wish to check if it contains a double, you can simply do something like:
#include <sstream>
std::istringstream iss(string_value);
double double_value;
char trailing_junk;
if (iss >> double_value && !(iss >> trailing_junk))
{
// can use the double...
}
As presented, this will reject things like "1.234q" or "-13 what?" but accept surrounding whitespace e.g. " 3.9E2 ". If you want to reject whitespace, try #include <iomanip> then if (iss >> std::noskipws >> double_value && iss.peek() == EOF) ....
You could also do this using old-style C APIs:
double double_value;
if (sscanf(string_value.c_str(), "%lf%*c", &double_value) == 1)
You cannot "cast" a string to a double, you can only convert it. strtod function will return a pointer to the character within the string where the conversion stopped, so you can decide what to do further. So you can use this function for conversion AND checking.
I'd recommend Boost's lexical_cast, which will throw an exception if the conversion fails.
Since this seems to be a C++ CLI related question and your string from the textbox might be a .NET string, you might want to check the static Double::Parse method. For more portable solutions see the other answers...
As stated already, strtod(3) is the answer.
bool is_double(const char* str) {
char *end = 0;
strtod(str, &end);
// Is the end point of the double the end of string?
return end == str + strlen(str);
}
To address #Ian Goldby's concern, if white space at the end of the sting is a concern, then:
bool is_double(const char* str) {
char *end = 0;
strtod(str, &end);
// Is the end point of the double plus white space the end of string?
return end + strspn(end, " \t\n\r") == str + strlen(str);
}
Simply convert it to a double value. If it succeeds, the input is valid.
Really, you shouldn't be writing your own rules for deciding what is valid. You'll never get exactly the same rules as the library function that will do the actual conversion.
My favourite recipe is to use sscanf(), and check the return value to ensure exactly one field was converted. For extra credit, use a %n parameter to check that no non-whitespace characters were left over.