Skip to content

Strings and streams

[Trim (remove leading and trailing white space)]
[Skip BOM (byte order marker)]
[Read complete text file into string]
[Streaming for user defined types]
[Read line of user input]
[Read words from user input]
[Read specific types from user input]
[Count words in a text file]

Trim (remove leading and trailing white space)

std::string Trim(const std::string& in_s)
{
    constexpr const char* whitespace{ " \t\r\n\v\f" };
    if (in_s.empty()) return in_s;
    const auto first{ in_s.find_first_not_of(whitespace) };
    if (first == std::string::npos) return in_s;
    const auto last{ in_s.find_last_not_of(whitespace) };
    return in_s.substr(first, last - first + 1);
}

Skip BOM (byte order marker)

A Windows UTF-8 file may contain 3 special bytes at the beginning of the file to signal the type of encoding. Before processing the real file contents the following function ensures, that the BOM bytes are skipped if they are existing:

void SkipBomForUtf8(auto& in_fs) // in_f relates to ifstream in example below
{
    const unsigned char boms[]{0xef, 0xbb, 0xbf};
    bool hasBom{true};
    for (const auto& ch: boms)
    {
        if ((unsigned char)in_fs.get() != ch)
            hasBom = false;
    }
    if (!hasBom)
        in_fs.seekg(0); // position to begin of file
}

Read complete text file into string

#include <fstream>

std::string ReadFileContentsToString(const std::string& in_filePath)
{
    // Read file contents to string
    std::ifstream myFile(in_filePath, std::ios_base::in);
    SkipBomForUtf8(); // if there is a chance for a BOM header!
    std::string text{};
    for (std::string line{}; std::getline(myFile, line); )
    {
        text += line;
    }
    return text;
}

Streaming for user defined types

struct MyPoint
{
    double x{};
    double y{};
};

std::ostream& operator<<(std::ostream& os, cobst MyPoint& p)
{
    os << '[' << p.x << '/' << p.y << ']';
    return os; 
}

See also formating of user defined types in std::format.

Read line of user input

std::cin usually reads one word at a time, but you can change it for input of whole lines:

Helper function to prompt the user:

bool Prompt(const std::string_view s, const std::string_view s2 = "")
{
    if (s2.size()) std::cout << std::format("{} ({}): ", s, s2);
    else std::cout << std::format("{}: ", s);
    std::cout.flush(); // ensure that output gets visible (even when new line is missing)
}

Read line with user input:

std::string GetUserInput()
{
    std::string line{};
    Prompt("Enter some words", "finish with [ret]");
    std::getline(std::cin, line);
    return line;
}

Read words from user input

std::cin reads single tokens separated by white space. This also avoids the overhead of reading a large file into memory at once (e.g. when a file is directed to input of the executable via command line MyApp.exe < SomeFile.txt).

for (std:string s{}; std::cin >> s)
{
    // process next token s here (e.g. analyze using regex)
}

Read specific types from user input

You can read specific types from std::cin. If the input cannot be converted the stream’s state is set to error and further input is no longer possible until the stream is reset.

Helper function to reset a stream:

void ClearInputStream()
{
    std::string s{};
    std::cin.clear(); // clears possible error state
    std::getline(std::cin, s); // read possible text from buffer and forget it
}

Read a double and an int from user input:

double a{};
int b{};
const char* p{"Enter a double and an int"};
for (Prompt(p); !(std::cin >> a >> b); Prompt(p))
{
    std::cout << "Wrong number format!\n";
    ClearInputStream();
}

As long as the entered format is wrong, the user will be prompted to enter correct data.

Count words in a text file

As default behaviour istream class reads one word at a time.

Helper function to count words:

std::size_t CountWords(auto& inputStream)
{
    using It = std::istream_iterator<std::string>;
    return std::distance(It{inputStream}, It{});
}

Count words in a given file:

std::ifstream inFile("SomeFilePath.txt", std::ios_base::in);
std::cout << std::format("There are {} words in the file.\n, CountWords(inFile));