0

I'm playing around with stringstreams, and I've got a line like:

10 651.23 Some longer name

I'd like to fetch it into uint, double and string like 10, 651.23, "Some longer name"

So I've tried

    iss >> quantity >> price >> std::noskipws >> name;

But it seems it isn't so easy as it looks. How can I get rest of the string including whitespaces?

Later I want to show the float with leading character and fixed precision:

    std::cout << std::setprecision(2) << std::fixed << std::setw(7) << std::setfill('.') << price;

However when I use std::fixed, my fill and width get rejected. How to fix that?

Thanks

Current code:

std::string filename;

std::ifstream is;
do {

    std::cout << "Podaj nazwę pliku do wczytania: " << std::endl;
    std::cin >> filename;
    is.open(filename.c_str());

    if(is.good()) break;
} while(true);

std::string name;
std::string wtf;
unsigned int quantity = 0;
double price = 0;
unsigned int i = 1;

while(is >> quantity >> price >> std::ws && std::getline(is, name)) {
    std::cout << "| ";
    std::cout << std::setw(2) << i++ << " | ";
    std::cout << std::setw(30) << std::setfill('.') << name << " | ";
    std::cout << std::setw(3) << std::setfill(' ') << quantity << " x ";
    std::cout << std::setprecision(2) << std::setw(10) << std::setfill(' ') << std::fixed << price << " zl | ";
    std::cout << std::setw(11) << std::setfill(' ') << quantity * price << " zl |";
    std::cout << std::endl;
}

The file looks like:

10 12999 TV55AA8000 smarttv ultra HD
5 12990 TV55AB600 smarttv ultraHD
20 9999 TV55GD2340s smarttv
10 7999 TV463400 funkcja 3D
20 1699.5 telewizor super!
30 1400 telewizor 3d 1000Hz
20 12999 telewizor nr 1
30 12000 EE55650 smarttv
10 1000 ED325400s
10 14350.00 EE80234
5 5600.00 TV60ED23231 smart tv plazma
10 2000.00 TV320323
1 12999.00 TV66EE231231 smarttv
12 3400.00 TV4243dss 3D
Misiur
  • 5,019
  • 8
  • 38
  • 54
  • 1
    Tried putting `std::setw(7) << std::setfill('.') <<` before `std::fixed`? Just a shot in the dark ... – πάντα ῥεῖ Jun 08 '14 at 19:11
  • Magic, I had it like this previously (or maybe not, as it looks ok now). If you can help me with other problem, post an answer and I'll mark it – Misiur Jun 08 '14 at 19:14
  • 1
    I didn't think about closing this answer. I'll post one if you don't wan to delete your question and the above comment solved it. I think it's useful for s.o. else, if no one else finds a duplicate that already applies. – πάντα ῥεῖ Jun 08 '14 at 19:16
  • As for your other concerns I've posted an answer meant as canonical once, which is meant to solve problems about how to read from structured input records: [Why does reading a struct record fields from std::istream fail, and how can I fix it?](http://stackoverflow.com/questions/23047052/why-does-reading-a-struct-record-fields-from-stdistream-fail-and-how-can-i-fi) – πάντα ῥεῖ Jun 08 '14 at 19:27
  • You'll need to provide a [SSCCE](http://sscce.org/) for the formatting problem: according to [my test](http://ideone.com/T8pf3M) setting the formatting flags like above just works. – Dietmar Kühl Jun 08 '14 at 19:34
  • Added current code. Thanks – Misiur Jun 08 '14 at 19:35
  • You code is still not an [SSCCE](http://sscce.org/)! [Here](http://ideone.com/KNJsjG) is my rendering of exactly your code *not* showing the problem, though! – Dietmar Kühl Jun 08 '14 at 19:48
  • Hm, with your stringstream it works like a charm. I can't use ideone as this requires file input... Updated the thread – Misiur Jun 08 '14 at 19:55
  • 1
    @Misiur _' I can't use ideone as this requires file input...'_ This could be usually replaced with `std::cin` somehow ... – πάντα ῥεῖ Jun 08 '14 at 20:35
  • Yup, but the thing is with mock stringstream/cin it works! Could the fact that file has windows \r\n line endings and I'm working on unix be a issue here? #e: Yup, that's the reason! But: is there a way to autodetect those endings so it works cross-platform, line-endings style independent? #e2: Oh, [found it](http://stackoverflow.com/questions/6089231/getting-std-ifstream-to-handle-lf-cr-and-crlf) – Misiur Jun 09 '14 at 10:52

2 Answers2

3

You may try placing the std::setw(7) << std::setfill('.') << manipulators before the std::fixed manipulator

std::cout << std::setprecision(2) << std::setw(7) << std::setfill('.') 
          << std::fixed << price;

But as for the standard definitions this shouldn't really matter.
Looks like this is a possible bug of your actual toolchain.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • 1
    If the order of how these formatting flags are set matters, there is something wrong with the corresponding implementation! These flags can be set independently and are inspected (by `std::num_put<...>::do_put()`) when formatting the value. The only flag which is a bit different is the width as it gets reset after each output operation using it but none of these operations other than formatting the `price` uses the width. – Dietmar Kühl Jun 08 '14 at 19:23
1

To incude whitespace when reading strings you can either change the definition of whitespace means (yes, this can be done by replacing the std::ctype<char> facet in a new std::locale and imbue()ing the stream with the thus constructed std::locale) or, a bit simpler, by using std::getline() to read the rest of the line. Assuming you want to ignore the leading whitespace in front of the trailing characters, you'd use std::ws when switching between formatted and unformatted input:

if (std::getline(iss >> quantity >> price >> std::ws, name)) {
    // do something with the result
}

I can't write input statements like the above without checking as I firmly believe that input shall always be verified for success after it is done.

The purpose of std::noskipws is to disable automatic skipping of whitespace by formatted input operations: the formatted input operations skip leading whitespace by default. However, the flag has no effect at all on how strings are are parsed except for skipping leading whitespace. With the std::noskipws flag set I'd think you'll just read an empty string as the extraction immediately finds a character not matching the formatting and stops.

With respect to the std::fixed settings for output I'm pretty sure that the setting should work but right now I can't verify what's going on.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • _'but right now I can't verify what's going on'_ Same for me :/, I'm a bit worrying I can't provide some facts, why it works the one way, but not the other. – πάντα ῥεῖ Jun 08 '14 at 19:23
  • @πάνταῥεῖ: if it depends on the order the flags are set I can only imagine that the implementation internally uses `snprintf()` and caches the formatting flags to be use, messing the settings up at some point. – Dietmar Kühl Jun 08 '14 at 19:26
  • Hm, I understand how this solution works, but it doesn't for some reason? When I check for !std::getline(iss >> quantity >> price >> std::ws, name)), the name is populated, but otherwise it is empty? My frontend mind can't grasp some C++ concepts, sorry. Should I include bigger slice of code? – Misiur Jun 08 '14 at 19:29
  • @Misiur: You should **not** negate the result to test for a successful read! The stream will convert to `true` if it its input operations were successful. ... and I'm pretty sure that my approach does works based on [my test](http://ideone.com/hmPhHT). – Dietmar Kühl Jun 08 '14 at 19:40
  • Good tip, I didn't check return type earlier. Now I've added current code, approach taken from http://stackoverflow.com/a/23047405/309240 . Something is still wrong though, name is not populated at all – Misiur Jun 08 '14 at 19:43