Home > Blockchain >  Why are my strings not being printed correctly?
Why are my strings not being printed correctly?

Time:01-03

I want to write a piece of code to create a list of random potions for D&D 5e from a few given parameter lists. And I was almost done, every bit of code working properly apart from a single line of code.

I expect an output of this sort: "The liquid is: Yellow with flecks of colour.". Instead, I get this: " with flecks of colour.". Basically, the entire part with: "The liquid is: " gets omitted. Weirdly enough it works fine in one single case, when the colour is "Dark Red".

Here is the minimal working example:

#include <iostream>
#include <vector>
#include <string>
#include <random>
#include <fstream>
#include <sstream>

int main(int argc, char** argv)
{
    std::vector<std::string> appearance;
    std::vector<std::string> appearance_2;
   
    std::ifstream d_appearance("appearance.txt");//20 entries
    std::ifstream d_appearance_2("appearance_2.txt");//20 entries

    std::string line;
    std::string line_2;

    for(int i = 0; i < 20; i  )
    {
        getline(d_appearance, line);
        appearance.push_back(line);

        getline(d_appearance_2, line_2);
        appearance_2.push_back(line_2);
    }

    std::random_device generator;
    std::uniform_int_distribution<int> twenty_dis(0,19);

    std::string p_appearance = appearance[twenty_dis(generator)];
    std::string p_appearance_2 = appearance_2[twenty_dis(generator)];

    for(int i = 0; i < 1; i  )
    {
        std::ostringstream s_look;
        s_look << "The liquid is; " << p_appearance << " with " << p_appearance_2;
        std::string look = s_look.str();
        std::cout << look << std::endl;
        std::cout << std::endl;
    }
    return 0;
}

I hope it's ok if I just put the text files here as code blocks: Appearance

Clear
Blue
Green
Red
Pale Green
Pink
Light Blue
White
Black
Dark Grey
Light grey
Yellow
Orange
Gold
Orange
Bronze
Metallic
Purple
Brown
Dark Red

Appearance_2

flecks of colour.
swirls of colour.
fizzing bubbles.
bubbles suspended in it.
some kind of bone floating in it.
leaves and flowers in it.
two separated liquid phases.
a bright glow.
a soft glow.
stripes of colour.
translucency.
a cloudy murkiness.
blood within it.
dirt floating in it.
chunks of metal in it.
some type of gore from a slain creature.
steam coming from it.
a face in the liquid.
constantly moving and shifting liquid.
a constant heat.

CodePudding user response:

That could be the problem with line endings. If you created the file in Windows (thus you have "\r\n" line endings) and use this file in Linux, the getline would work differently. It will use '\n' as a delimiter, but will treat '\r' as a separate string. As the result you may get some appearences equal to "\r". At the end of the day you could output that:

std::ostringstream s_look;
s_look << "The liquid is; " << "\r" << " with " << p_appearance_2;
std::string look = s_look.str();
std::cout << look << std::endl;
std::cout << std::endl;

That will override the beginning of the string, so you don't see the "The liquid is; " in the output.

CodePudding user response:

It looks like an answer has been accepted, and I'm glad that the issue was found out.

I didn't run into this personally, but I was also creating the files from scratch.

I did, however, make some small adjustments to your code. The only really meaningful change has to do with the random number selections. std::random_device polls your hardware's entropy pool. This is a limited resource, and a bit slow. Typically, one should use the entropic value to seed a PRNG, which is much faster and close enough to truly random.

I created a distribution for each of your colors and distributions, so that both name pools remain completely accessible, even if their sizes differ.

#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include <random>
#include <string>
#include <vector>

// This is not necessary, I just wanted to use std::copy to read the files.
// A while (std::getline(descriptionStream, tmp)) loop would work just as well.
namespace util {
class LineString {
 public:
  friend std::istream& operator>>(std::istream& sin, LineString& obj) {
    return std::getline(sin, obj.m_string);
  }

  operator std::string() const { return m_string; }

 private:
  std::string m_string;
};
}  // namespace util

int main(int argc, char** argv) {
  std::vector<std::string> colors;
  std::vector<std::string> descriptions;

  std::ifstream colorStream("color.txt");
  std::ifstream descriptionStream("description.txt");
  if (!colorStream || !descriptionStream) {
    std::cerr << "Error opening one of the input files. Exiting...\n";
    return 1;
  }

  std::copy(std::istream_iterator<std::string>(colorStream),
            std::istream_iterator<std::string>(), std::back_inserter(colors));
  std::copy(std::istream_iterator<util::LineString>(descriptionStream),
            std::istream_iterator<util::LineString>(),
            std::back_inserter(descriptions));
  colorStream.close();
  descriptionStream.close();

  // Using your entropy source (std::random_device) to seed a PRNG and
  // subsequently using the PRNG to feed the distributions.
  std::mt19937 generator(std::random_device{}());
  std::uniform_int_distribution<std::size_t> colorDist(0, colors.size() - 1);
  std::uniform_int_distribution<std::size_t> descriptionDist(
      0, descriptions.size() - 1);

  for (int i = 0; i < 30; i  ) {
    std::string look = "The liquid is: "   colors.at(colorDist(generator))  
                       " with "   descriptions.at(descriptionDist(generator));
    std::cout << look << "\n\n";
  }
  return 0;
}
  • Related