why replace spaces with %20 program crashes? - c++

I wrote the following code to replace all the spaces in string s with string r (20%). E.g. s = "Mr John Smith", after running the code it should be "Mr20%John20%Smith".
My code crashes and it looks to me like a memory leak, but have no clue why it happens. Thank you.
void ReplaceStr(string &s, string &r)
{
int i = 0;
for(string::iterator it = s.begin(); it != s.end(); it++,i++)
{
if( *it == ' ')
{
s.replace(i,1,r);
}
}
}

The documentation for replace says "[a]ny iterators, pointers and references related to this object may be invalidated." Your iterator is an iterator into a version of the string that no longer exists, so you can't keep incrementing it, dereferencing it, comparing it, and so on.

When the replacement length is not equal to the the target size, building a copy is generally easier and nearly as efficient.
void ReplaceSpaces(std::string &s, const std::string &r) {
std::string result;
result.reserve(s.size());
for (char c : s) {
if (c == ' ') result += r;
else result.push_back(c);
}
using std::swap;
swap(s, result);
}

A much better option vould be not to use iterators at all:
void ReplaceStr(string &s, string &r)
{
for (int i = 0; i < s.lenght(); )
{
if (s[i] == ' ')
{
s.replace(i,1,r);
i += r.lenght();
}
else
i++;
}
}
Quick and easy. Maybe r's lenght could be stored in a constant to improve the performance a little bit.
void ReplaceStr(string &s, const string &r)
{
const int rSize = r.lenght();
for (int i = 0; i < s.lenght(); )
{
if (s[i] == ' ')
{
s.replace(i,1,r);
i += rSize;
}
else
i++;
}
}
And this works because the leght of s gets constantly updated.

Related

Check if two given strings are isomorphic to each other c++, not sure why it's wrong

class Solution {
public:
bool isIsomorphic(string s, string t) {
vector <int> sfreq (26,0);
vector <int> tfreq (26,0);
for (int i=0; i<s.size(); i++) {
sfreq[s[i]-'a']++;
tfreq[t[i]-'a']++;
}
if (sfreq != tfreq) {
return false;
}
return true;
}
};
Hi, this is my code in c++, I saw something similar from https://www.geeksforgeeks.org/check-if-two-given-strings-are-isomorphic-to-each-other/ but my answer shows it's wrong. Can anyone please tell me why it's wrong?
You completely misunderstood the description.
Your question suggests that any permutation of characters in input do not change answer. Also you assumed that histograms are equal.
Position of character is important. Each position in both strings creates a unique pair.
Here my code which passed:
class Solution {
public:
static bool canMapInOneDirection(std::string_view s, std::string_view t)
{
const auto n = s.size();
std::array<char, 128> mapping{};
for(size_t i = 0; i < n; ++i) {
if (mapping[s[i]] == 0) mapping[s[i]] = t[i];
else if (mapping[s[i]] != t[i]) return false;
}
return true;
}
bool isIsomorphic(string s, string t)
{
return s.size() == t.size() && canMapInOneDirection(s, t) && canMapInOneDirection(t, s);
}
};
And test cases you can use to test your code:
s
t
answear
"a"
"b"
true
"aa"
"bb"
true
"ab"
"aa"
false
"aabbcc"
"aabcbc"
false
https://godbolt.org/z/61EcTK5fq
This not a question about anagrams or directly about character frequencies. It is about pattern. It's about having a character-by-character mapping that makes one string into the other. AABC is isomorphic to XXYZ but not isomorphic to BCAA.
When we talk about Isomorphism (same form) it's often a good idea to look for a signature representation.
So instead of determining if two strings are isomorphic I've decided to define a unique signature representation and determine isomorphism if two strings map to the same signature.
I've used std::vector<char> for the signature representation such that the first character (if any) is assigned 0 the second (previously unseen) character 1 and so on.
So a string like MOON has signature {0,1,1,2} because the middle characters are the only repeats. MOON is isomorphic to BOOK but not NOON.
The advantage of such a strategy is that if many strings are to be compared to find groups of mutually isomorphic strings each string need only be converted to its signature once.
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
std::vector<char> get_signature(const std::string& str){
std::vector<char> result;
std::unordered_map<char,char> map;
char curr{1};
for(auto cchar : str){
char& c{map[cchar]};
if(c==0){
c=curr++;
}
result.emplace_back(c-1);
}
return result;
}
int check_signature(const std::string& str, const std::vector<char>& expect ){
const auto result{get_signature(str)};
return result==expect?0:1;
}
int main() {
int errors{0};
{
const std::string str{"ABCDE"};
const std::vector<char> signat{0,1,2,3,4};
errors+=check_signature(str,signat);
}
{
const std::string str{"BABY"};
const std::vector<char> signat{0,1,0,2};
errors+=check_signature(str,signat);
}
{
const std::string str{"XXYZX"};
const std::vector<char> signat{0,0,1,2,0};
errors+=check_signature(str,signat);
}
{
const std::string str{"AABCA"};
const std::vector<char> signat{0,0,1,2,0};
errors+=check_signature(str,signat);
}
{
const std::string str{""};
const std::vector<char> signat{};
errors+=check_signature(str,signat);
}
{
const std::string str{"Z"};
const std::vector<char> signat{0};
errors+=check_signature(str,signat);
}
if(get_signature("XXYZX")!=get_signature("AABCA")){
++errors;
}
if(get_signature("MOON")==get_signature("AABCA")){
++errors;
}
if(get_signature("MOON")!=get_signature("BOOK")){
++errors;
}
if(get_signature("MOON")==get_signature("NOON")){
++errors;
}
if(errors!=0){
std::cout << "ERRORS\n";
}else{
std::cout << "SUCCESS\n";
}
return 0;
}
Expected Output: SUCCESS
Because you are missing a loop.
Note that, it still requires more corner case checking to make it fully work. The second approach properly handles all cases.
class Solution {
public:
bool isIsomorphic(string s, string t) {
vector <int> sfreq (26,0);
vector <int> tfreq (26,0);
for (int i=0; i < s.size(); i++) {
sfreq[s[i]-'a']++;
tfreq[t[i]-'a']++;
}
// character at the same index (can be different character) should have the same count.
for(int i= 0; i < s.size(); i++)
if (sfreq[s[i]-'a'] != tfreq[t[i]-'a']) return false;
return true;
}
};
But the above solution only works if there is direct index mappping between characters. Like, AAABBCA and XXXYYZX. But fails for bbbaaaba and aaabbbba. Also, no uppercase, lowercase handled. The link you shared contains the wrong implementation which is mentioned in the comment.
The solution below works as I tested.
class Solution {
public:
bool isIsomorphic(string s, string t) {
vector<int> scount(128, -1), tcount(128, -1);
for (int i = 0; i < s.size(); ++i) {
auto schar = s[i], tchar = t[i];
if (scount[schar] == -1) {
scount[schar] = tchar;
if (tcount[tchar] != -1) return false;
else tcount[tchar] = schar;
} else if (scount[schar] != tchar) return false;
}
return true;
}
};

How do I read a string char by char in C++?

I need to read a string char by char in order to perform some controls on it. Is it possible to do that? Have I necessarily got to convert it to a char array?
I tried to point at single chars with string_to_control[i] and then increase i to move, but this doesn't seem to work.
As an example, I post a piece of the code for the control of parenthesis.
bool Class::func(const string& cont){
const string *p = &cont;
int k = 0;
//control for parenthesis
while (p[k].compare('\0') != 0) {
if (p[k].compare("(") == 0) { ap++; };
if (p[k].compare(")") == 0) { ch++; };
k++;
};
//...
};
The string is copied alright, but as soon as I try the first comparison an exception is thrown.
EDIT: I add that I would like to have different copies of the initial string cont (and move on them, rather than on cont directly) in order to manipulate them (later on in the code, I need to verify that certain words are in the right place).
The simplest way to iterate through a string character by character is a range-for:
bool Class::func(const string& cont){
for (char c : cont) {
if (c == '(') { ap++; }
if (c == ')') { ch++; }
}
//...
};
The range-for syntax was added in C++11. If, for some reason, you're using an old compiler that doesn't have C++11 support, you can iterate by index perfectly well without any casts or copies:
bool Class::func(const string& cont){
for (size_t i = 0; i < cont.size(); ++i) {
if (cont[i] == '(') { ap++; }
if (cont[i] == ')') { ch++; }
}
//...
};
If you just want to count the opening and closing parentheses take a look at this:
bool Class::func(const string& cont) {
for (const auto c : cont) {
switch (c) {
case '(': ++ap; break;
case ')': ++ch; break;
}
}
// ...
}
const string *p = &cont;
int k = 0;
while (p[k].compare('\0') != 0)
Treats p as if it were an array, as p only points to a single value your code has undefined behaviour when k is non-zero. I assume what you actually wanted to write was:
bool Class::func(const string& cont){
while (cont[k] != '\0') {
if (cont[k] == '(') { ap++; };
if (cont[k] == ') { ch++; };
k++;
};
};
A simpler way would be to iterate over std::string using begin() and end() or even more simply just use a range for loop:
bool Class::func(const string& cont){
for (char ch : cont) {
if (ch == '(') { ap++; };
if (ch == ')') { ch++; };
};
};
If you want to copy your string simply declare a new string:
std::string copy = cont;
The std::string::operator[] overload allows expressions such as cont[k]. Your code treats p as an array of std::string rather then an array of characters as you intended. That could be corrected by:
const string &p = cont;
but is unnecessary since you can already access cont directly.
cont[k] has type char so calling std::string::compare() is not valid. You can compare chars in the normal manner:
cont[k] == '('`
You should also be aware that before C++11 the end of a std::string is not delimited by a \0 like a C string (there may happen to be a NUL after the string data, but that is trusting to luck). C++11 does guarantee that, but probably only to "fix" older code that made the assumption that it was.
If you use std::string::at rather then std::string::operator[] an exception will be thrown if you exceed the bounds. But you should use either range-based for, a std::string::iterator or std::string::length() to iterate a string to the end.
If you don't want to use iterators std::string also overloads operator[], so you can access the chars like you would do with a char[].
cont[i] will return the character at index i for example, then you can use == to compare it to another char:
bool Class::func(const string& cont){
int k = 0;
while (k < cont.length()) {
if (cont[k] == '(') { ap++; };
if (cont[k] == ')') { ch++; };
k++;
};
};
To count parentheses, you can use std::count algorithm from the standard library:
/* const */ auto ap = std::count(cont.begin(), cont.end(), '(');
/* const */ auto ch = std::count(cont.begin(), cont.end(), ')');
The string will be traversed twice.
For single traversal you can implement a generic function (requires C++17):
template<class C, typename... Ts>
auto count(const C& c, const Ts&... values) {
std::array<typename C::difference_type, sizeof...(Ts)> counts{};
for (auto& value : c) {
auto it = counts.begin();
((*it++ += (value == values)), ...);
}
return counts;
}
and then write
/* const */ auto [ap, ch] = count(cont, '(', ')');
First convert the string to a char array like this:
bool Class::func(const string& cont){
char p[cont.size() + 1];
strcpy(p, cont.c_str());
int k = 0;
//control for parenthesis
while (p[k].compare('\0') != 0) {
if (p[k].compare("(") == 0) { ap++; };
if (p[k].compare(")") == 0) { ch++; };
k++;
};
//...
};
You could do what you want with an algorithm, which means you can avoid the array conversion:
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm> // std::count
int main()
{
std::string s = "hi(there),(now))";
int ap = std::count (s.c_str(), s.c_str()+s.size(), '(');
int ch = std::count (s.c_str(), s.c_str()+s.size(), ')');
std::cout << ap << "," << ch << '\n'; // prints 2,3
return 0;
}

How can I speed up parsing of large strings?

So I've made a program that reads in various config files. Some of these config files can be small, some can be semi-large (largest one is 3,844 KB).
The read in file is stored in a string (in the program below it's called sample).
I then have the program extract information from the string based on various formatting rules. This works well, the only issue is that when reading larger files it is very slow....
I was wondering if there was anything I could do to speed up the parsing or if there was an existing library that does what I need (extract string up until a delimiter & extract string string in between 2 delimiters on the same level). Any assistance would be great.
Here's my code & a sample of how it should work...
#include "stdafx.h"
#include <string>
#include <vector>
std::string ExtractStringUntilDelimiter(
std::string& original_string,
const std::string& delimiter,
const int delimiters_to_skip = 1)
{
std::string needle = "";
if (original_string.find(delimiter) != std::string::npos)
{
int total_found = 0;
auto occurance_index = static_cast<size_t>(-1);
while (total_found != delimiters_to_skip)
{
occurance_index = original_string.find(delimiter);
if (occurance_index != std::string::npos)
{
needle = original_string.substr(0, occurance_index);
total_found++;
}
else
{
break;
}
}
// Remove the found string from the original string...
original_string.erase(0, occurance_index + 1);
}
else
{
needle = original_string;
original_string.clear();
}
if (!needle.empty() && needle[0] == '\"')
{
needle = needle.substr(1);
}
if (!needle.empty() && needle[needle.length() - 1] == '\"')
{
needle.pop_back();
}
return needle;
}
void ExtractInitialDelimiter(
std::string& original_string,
const char delimiter)
{
// Remove extra new line characters
while (!original_string.empty() && original_string[0] == delimiter)
{
original_string.erase(0, 1);
}
}
void ExtractInitialAndFinalDelimiters(
std::string& original_string,
const char delimiter)
{
ExtractInitialDelimiter(original_string, delimiter);
while (!original_string.empty() && original_string[original_string.size() - 1] == delimiter)
{
original_string.erase(original_string.size() - 1, 1);
}
}
std::string ExtractStringBetweenDelimiters(
std::string& original_string,
const std::string& opening_delimiter,
const std::string& closing_delimiter)
{
const size_t first_delimiter = original_string.find(opening_delimiter);
if (first_delimiter != std::string::npos)
{
int total_open = 1;
const size_t opening_index = first_delimiter + opening_delimiter.size();
for (size_t i = opening_index; i < original_string.size(); i++)
{
// Check if we have room for opening_delimiter...
if (i + opening_delimiter.size() <= original_string.size())
{
for (size_t j = 0; j < opening_delimiter.size(); j++)
{
if (original_string[i + j] != opening_delimiter[j])
{
break;
}
else if (j == opening_delimiter.size() - 1)
{
total_open++;
}
}
}
// Check if we have room for closing_delimiter...
if (i + closing_delimiter.size() <= original_string.size())
{
for (size_t j = 0; j < closing_delimiter.size(); j++)
{
if (original_string[i + j] != closing_delimiter[j])
{
break;
}
else if (j == closing_delimiter.size() - 1)
{
total_open--;
}
}
}
if (total_open == 0)
{
// Extract result, and return it...
std::string needle = original_string.substr(opening_index, i - opening_index);
original_string.erase(first_delimiter, i + closing_delimiter.size());
// Remove new line symbols
ExtractInitialAndFinalDelimiters(needle, '\n');
ExtractInitialAndFinalDelimiters(original_string, '\n');
return needle;
}
}
}
return "";
}
int main()
{
std::string sample = "{\n"
"Line1\n"
"Line2\n"
"{\n"
"SubLine1\n"
"SubLine2\n"
"}\n"
"}";
std::string result = ExtractStringBetweenDelimiters(sample, "{", "}");
std::string LineOne = ExtractStringUntilDelimiter(result, "\n");
std::string LineTwo = ExtractStringUntilDelimiter(result, "\n");
std::string SerializedVector = ExtractStringBetweenDelimiters(result, "{", "}");
std::string SubLineOne = ExtractStringUntilDelimiter(SerializedVector, "\n");
std::string SubLineTwo = ExtractStringUntilDelimiter(SerializedVector, "\n");
// Just for testing...
printf("LineOne: %s\n", LineOne.c_str());
printf("LineTwo: %s\n", LineTwo.c_str());
printf("\tSubLineOne: %s\n", SubLineOne.c_str());
printf("\tSubLineTwo: %s\n", SubLineTwo.c_str());
system("pause");
}
Use string_view or a hand rolled one.
Don't modify the string loaded.
original_string.erase(0, occurance_index + 1);
is code smell and going to be expensive with a large original string.
If you are going to modify something, do it in one pass. Don't repeatedly delete from the front of it -- that is O(n^2). Instead, procceed along it and shove "finished" stuff into an output accumulator.
This will involve changing how your code works.
You're reading your data into a string. "Length of string" should not be a problem. So far, so good...
You're using "string.find().". That's not necessarily a bad choice.
You're using "string.erase()". That's probably the main source of your problem.
SUGGESTIONS:
Treat the original string as "read-only". Don't call erase(), don't modify it.
Personally, I'd consider reading your text into a C string (a text buffer), then parsing the text buffer, using strstr().
Here is a more efficient version of ExtractStringBetweenDelimiters. Note that this version does not mutate the original buffer. You would perform subsequent queries on the returned string.
std::string trim(std::string buffer, char what)
{
auto not_what = [&what](char ch)
{
return ch != what;
};
auto first = std::find_if(buffer.begin(), buffer.end(), not_what);
auto last = std::find_if(buffer.rbegin(), std::make_reverse_iterator(first), not_what).base();
return std::string(first, last);
}
std::string ExtractStringBetweenDelimiters(
std::string const& buffer,
const char opening_delimiter,
const char closing_delimiter)
{
std::string result;
auto first = std::find(buffer.begin(), buffer.end(), opening_delimiter);
if (first != buffer.end())
{
auto last = std::find(buffer.rbegin(), std::make_reverse_iterator(first),
closing_delimiter).base();
if(last > first)
{
result.assign(first + 1, last);
result = trim(std::move(result), '\n');
}
}
return result;
}
If you have access to string_view (c++17 for std::string_view or boost::string_view) you could return one of these from both functions for extra efficiency.
It's worth mentioning that this method of parsing a structured file is going to cause you problems down the line if any of the serialised strings contains a delimiter, such as a '{'.
In the end you'll want to write or use someone else's parser.
The boost::spirit library is a little complicated to learn, but creates very efficient parsers for this kind of thing.

Is there an alternative to using str.substr( ) to extract a substring at a given position?

I am trying to compare two std::strings, and decide if string A is the same as string B, but with the insertion or deletion of a single character.
Otherwise it returns false.
For example: "start" and "strt" or "ad" and "add"
Currently:
if(((sizeA - sizeB) != 1)
&& ((sizeB - sizeA) != 1))
{
return false;
}
if(sizeA < sizeB)
{
for(int i = 0; i < sizeA; ++i)
{
if(stringA[i] != stringB[i])
{
if(stringA.substr(i)
== stringB.substr(i + 1))
{
return true;
}
else return false;
}
}
} //with another loop that runs only if stringA is larger than stringB
This works flawlessly, but gprof tells me that this function is being bogged down.
I tried converting the for loop to use iterators to access the chars, but this doubled my run time.
Ive narrowed it down to my use of std::string.substr( ) because it is constructing new strings each time stringA and stringB differ in size by 1.
When the first character differs, I need a more efficient way to check if I were to delete that character, would the two strings then be equal?
It seems, once it is known whether there is a one character difference the comparison can be done more effective with a single pass over the string: find the location of the difference, skip the character, and see if the tail is the same. To that end it is obviously necessary to know which one is the smaller string but that's trivial to determine:
bool oneCharDiff(std::string const& shorter, std::string const& longer) {
if (shorter.size() + 1u != longer.size() {
return false;
}
typedef std::string::const_iterator const_iterator;
std::pair<const_iterator, const_iterator> p
= std::mismatch(shorter.begin(), shorter.end(), longer.begin());
return std::equal(p.first, shorter.end(), p.second + 1);
}
bool atMostOneCharDiff(std::string const& s0, std::string const& s1) {
if (s0.size() < s1.size()) {
return oneCharDiff(s0, s1);
else if (s1.size() < s0.size()) {
return oneCharDiff(s1, s0);
}
else {
return s0 == s1;
}
}
Try:
if (stringA.compare(i, stringA.npos, stringB, i+1, stringB.npos) == 0) {
/* the strings are equal */
}
In this write-up, that's version (3) of std::basic_string::compare.
If your compiler supports it it may be worth checking out the new ISO/IEC TS 19568:xxxx Technical Specification string_view class.
It provides an immutable view of a string through references without copying the string itself so it promises to be much more efficient when dealing with substrings.
#include <experimental/string_view>
using std::experimental::string_view;
bool func(string_view svA, string_view svB)
{
// ... stuff
if(svA.size() < svB.size())
{
for(int i = 0; i < svA.size(); ++i)
{
if(svA[i] != svB[i])
{
if(svA.substr(i)
== svB.substr(i + 1))
{
return true;
}
else return false;
}
}
}
// ... stuff
return false;
}
As you can see it works pretty much like a drop-in replacement for std::string (or const char* etc...). Simply pass your normal std::string objects as arguments to the function and the string_view parameters will initialize from the passed in strings.

Efficient way to check if std::string has only spaces

I was just talking with a friend about what would be the most efficient way to check if a std::string has only spaces. He needs to do this on an embedded project he is working on and apparently this kind of optimization matters to him.
I've came up with the following code, it uses strtok().
bool has_only_spaces(std::string& str)
{
char* token = strtok(const_cast<char*>(str.c_str()), " ");
while (token != NULL)
{
if (*token != ' ')
{
return true;
}
}
return false;
}
I'm looking for feedback on this code and more efficient ways to perform this task are also welcome.
if(str.find_first_not_of(' ') != std::string::npos)
{
// There's a non-space.
}
In C++11, the all_of algorithm can be employed:
// Check if s consists only of whitespaces
bool whiteSpacesOnly = std::all_of(s.begin(),s.end(),isspace);
Why so much work, so much typing?
bool has_only_spaces(const std::string& str) {
return str.find_first_not_of (' ') == str.npos;
}
Wouldn't it be easier to do:
bool has_only_spaces(const std::string &str)
{
for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
{
if (*it != ' ') return false;
}
return true;
}
This has the advantage of returning early as soon as a non-space character is found, so it will be marginally more efficient than solutions that examine the whole string.
To check if string has only whitespace in c++11:
bool is_whitespace(const std::string& s) {
return std::all_of(s.begin(), s.end(), isspace);
}
in pre-c++11:
bool is_whitespace(const std::string& s) {
for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
if (!isspace(*it)) {
return false;
}
}
return true;
}
Here's one that only uses STL (Requires C++11)
inline bool isBlank(const std::string& s)
{
return std::all_of(s.cbegin(),s.cend(),[](char c) { return std::isspace(c); });
}
It relies on fact that if string is empty (begin = end) std::all_of also returns true
Here is a small test program: http://cpp.sh/2tx6
Using strtok like that is bad style! strtok modifies the buffer it tokenizes (it replaces the delimiter chars with \0).
Here's a non modifying version.
const char* p = str.c_str();
while(*p == ' ') ++p;
return *p != 0;
It can be optimized even further, if you iterate through it in machine word chunks. To be portable, you would also have to take alignment into consideration.
I do not approve of you const_casting above and using strtok.
A std::string can contain embedded nulls but let's assume it will be all ASCII 32 characters before you hit the NULL terminator.
One way you can approach this is with a simple loop, and I will assume const char *.
bool all_spaces( const char * v )
{
for ( ; *v; ++v )
{
if( *v != ' ' )
return false;
}
return true;
}
For larger strings, you can check word-at-a-time until you reach the last word, and then assume the 32-bit word (say) will be 0x20202020 which may be faster.
Something like:
return std::find_if(
str.begin(), str.end(),
std::bind2nd( std::not_equal_to<char>(), ' ' ) )
== str.end();
If you're interested in white space, and not just the space character,
then the best thing to do is to define a predicate, and use it:
struct IsNotSpace
{
bool operator()( char ch ) const
{
return ! ::is_space( static_cast<unsigned char>( ch ) );
}
};
If you're doing any text processing at all, a collection of such simple
predicates will be invaluable (and they're easy to generate
automatically from the list of functions in <ctype.h>).
it's highly unlikely you'll beat a compiler optimized naive algorithm for this, e.g.
string::iterator it(str.begin()), end(str.end())
for(; it != end && *it == ' '; ++it);
return it == end;
EDIT: Actually - there is a quicker way (depending on size of string and memory available)..
std::string ns(str.size(), ' ');
return ns == str;
EDIT: actually above is not quick.. it's daft... stick with the naive implementation, the optimizer will be all over that...
EDIT AGAIN: dammit, I guess it's better to look at the functions in std::string
return str.find_first_not_of(' ') == string::npos;
I had a similar problem in a programming assignment, and here is one other solution I came up with after reviewing others. here I simply create a new sentence without the new spaces. If there are double spaces I simply overlook them.
string sentence;
string newsent; //reconstruct new sentence
string dbl = " ";
getline(cin, sentence);
int len = sentence.length();
for(int i = 0; i < len; i++){
//if there are multiple whitespaces, this loop will iterate until there are none, then go back one.
if (isspace(sentence[i]) && isspace(sentence[i+1])) {do{
i++;
}while (isspace(sentence[i])); i--;} //here, you have to dial back one to maintain at least one space.
newsent +=sentence[i];
}
cout << newsent << "\n";
Hm...I'd do this:
for (auto i = str.begin(); i != str.end() ++i)
if (!isspace(i))
return false;
Pseudo-code, isspace is located in cctype for C++.
Edit: Thanks to James for pointing out that isspace has undefined behavior on signed chars.
If you are using CString, you can do
CString myString = " "; // All whitespace
if(myString.Trim().IsEmpty())
{
// string is all whitespace
}
This has the benefit of trimming all newline, space and tab characters.