Replacing a substring with a space character - c++

I am given a string and I have to remove a substring from it. Namely WUB, and replace it with a space character.
There are 2 WUB's between ÁRE' and 'THE'. SO the first condition in if statement is for not printing two blank spaces but on executing the code two blank spaces are being printed.
Input: WUBWEWUBAREWUBWUBTHEWUBCHAMPIONSWUBMYWUBFRIENDWUB
Output: WE ARE THE CHAMPIONS MY FRIEND
Here is my code so far:
#include <iostream>
using namespace std;
int main()
{
const string check = "WUB";
string s, p;
int ct = 0;
cin >> s;
for (int i = 0; i < s.size(); i++)
{
if (s[i] == 'W' && s[i+1] == 'U' && s[i+2] == 'B')
{
i += 2;
if (p[ct] == '32' || p.empty())
{
continue;
}
else
{
p += ' ';
ct++;
}
}
else
{
p += s[i];
ct++;
}
}
cout << p;
return 0;
}
Why is the first if statement never executed?

2 things are going to break your code:
you are doing a for loop like this int i=0;i<s.size() but reading (s[i]=='W' && s[i+1]=='U' && s[i+2]=='B')
and here: if(p[ct]=='32') you mean for sure if(p[ct]==32) or if(p[ct]==' ')

This condition
if(p[ct]=='32')
should read either
if(p[ct]==32)
or
if(p[ct]==' ')
that is, compare to the numeric value of the space character or to the space character itself.
Additionally, when your i grows close to the string's length, the subexpressions s[i+1] and s[i+2] may reach non-exiting characters of the string. You should continue looping with a i<s.length()-2 condition.
EDIT
For a full solution you need to fully understand the problem you want to solve. The problem statement is a bit vague:
remove a substring ("WUB") from (a given string). And put a space inplace of it if required.
You considered the last condition, but not deeply enough. What does it mean, 'if required'? Replacement is not required if the resulting string is empty or you appended a space to it already (when you encounter a second of further consecutive WUB). It is also not necessary if you are at WUB, but there is nothing more following it - except possibly another WUBs...
So, when you find a "WUB" substring it is too early to decide if a space is needed. You know you need a space when you find a non-WUB text following some WUB (or WUBs) and there was some text before those WUB(s).

There are actually three bugs here, so it's probably worth to conclude them in one answer:
The first condition:
if (s[i] == 'W' && s[i+1] == 'U' && s[i+2] == 'B')
is out of bounds for the last two characters. One fix would be to check the length first:
if(i < s.length() - 2 && s[i] == 'W' && s[i+1] == 'U' && s[i+2] == 'B')
There's a multicharacter-literal in
if (p[ct] == '32' || p.empty())
Use ' ' or 32 or std::isspace instead. IMO the last one is the best.
In the same condition
p[ct] == '32'
is always out of bounds: ct is equal to p.length(). (Credits to Some programmer dude, who mentioned this in the comments!) The variable ct is also redundant, since std::string knows it's length. I suggest to use std::string::back() to access the last character and reorder the condition as so:
if (p.empty() || std::isspace(p.back()))

The algorithm to this program is on the right track.
However, there is a few issues..
The for loop goes out of index. A way to solve this issue is substracting the size -3. Something like this.
for (int i=0; i<s.size()-3; i++) {
}
I do not suggest using other variables as counters like ct. In this case ct can reach an index out of bound error by using p[ct] inside the for loop.
Creating a string and using append() function will be a better solution. In this case, we iterate through each character in the string and if we find "WUB" then we append a " ". Otherwise, we append the character.
I highly recommend to write the first if() statement using substring() from C++.
This makes the code easier to read.
Substring creates and returns a new string that starts from a specific position to an ending position. Here is the syntax
syntax: substr(startingIndex, endingIndex);
endingIndex is exclusive
#include <string>
#include <iostream>
int main() {
string s, p;
cin >> s;
for(int i=0;i<s.size()-3;i++) {
if (s.substr(i, i+3) == "WUB") {
p.append(" ");
} else {
p.append(s.substr(i,i+1));
i++;
continue;
}
i+=3;
}
}

Related

Remove out excess spaces from string in C++

I have written program for removing excess spaces from string.
#include <iostream>
#include <string>
void RemoveExcessSpaces(std::string &s) {
for (int i = 0; i < s.length(); i++) {
while (s[i] == ' ')s.erase(s.begin() + i);
while (s[i] != ' ' && i < s.length())i++;
}
if (s[s.length() - 1] == ' ')s.pop_back();
}
int main() {
std::string s(" this is string ");
RemoveExcessSpaces(s);
std::cout << "\"" << s << "\"";
return 0;
}
One thing is not clear to me. This while (s[i] == ' ')s.erase(s.begin() + i); should remove every space in string, so the output would be thisisstring, but I got correct output which is this is string.
Could you explain me why program didn't remove one space between this and is and why I got the correct output?
Note: I cannot use auxiliary strings.
That is because when your last while loop finds the space between your characters (this is) control pass to increment part of your for loop which will increase the value of int i then it will point to next character of given string that is i(this is string) that's why there is space between (this is).
Your second while loop will break when s[i]==' '. But then your for loop will increment i and s[i] for that i will be skipped. This will happen for every first space character after each word.

C++ Check and modify strings / String subscript out of range

I'm trying to make a program which modifies words in a specific manner:
It should first check the ending of the words and then proceed to modify them. I won't explain it in detail, because it doesn't make much sense in English.
I've written the following:
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
cout << "Por favor, introduzca los gentilicios separados por la tecla enter, para finalizar, escriba OK" << '\n';
string name[10];
string place[10];
for (int i(0); (i < 10); i++)
{
getline(cin, name[i]);
if (name[i] == "OK") //Error here
break;
}
for (int i(0); (i < 10); i++)
{
place[i] = name[i];
if (name[i][name[i].length() - 1] == 'c')
{
if (name[i][name[i].length()] == 'a' || (name[i][name[i].length()] == 'o') || (name[i][name[i].length()] == 'u'))
place[i][place[i].length() - 1] = 'q';
place[i][place[i].length()] = 'u';
place[i] = place[i] + "istan";
}
else if (name[i][name[i].length()] == 'a' || name[i][name[i].length()] == 'e' || name[i][name[i].length()] == 'i' || name[i][name[i].length()] == 'o' || name[i][name[i].length()] == 'u')
{
place[i][place[i].length()] = 'i';
place[i] = place[i] + "stan";
}
if (name[i][name[i].length()] == 's')
place[i] = place[i] + "tan";
else {
place[i] = place[i] + "istan";
}
place[i][0] = toupper(place[i][0]);
}
for (int i(0); (i < 10); i++)
{
cout << place[i] << '\n';
}
return 0;
}
Now I'm getting the error "String subscript out of range" . I would like to know where is the error exactly. I know it prompts when I write "OK", at line "18".
The condition i <= sizeof(name). sizeof(name) returns the size of the array in bytes, not the number of elements in it. Even if it returned the number of elements, <= is wrong and would cause an out-of-bounds access (should be <).
To loop through all elements in an array, you can use the range-based for-loop:
for(auto& n : name)
{
getline(cin, n);
if (n == "OK")
break;
}
Or to do it the right way with the C-style for-loop:
for (int i(0); i < sizeof(name)/sizeof(name[0]; i++)
{
…
}
Here:
for (int i(0); (i <= sizeof(name)); i++)
sizeof(name) is the size in bytes of the array, which as it is an array of std::string is effectively meaningless. If you want to iterate over 10 items, simply say so (note also that less-than-or-equals is also wrong here):
for (int i = 0; i < 10; i++)
And here:
getline(cin, name[i]);
whenever you perform input you must check the return value of the input function and handle any errors:
if( ! getline(cin, name[i]) ) {
// handle error somehow
}
And here:
string * p;
you do not want to be dealing with pointers to strings. If you want to access the contents of a string, you use operator[] or other string member functions on the string.
std::strings are not like cstrings. You can just grab a part of them using a std::string*. When you do
*(p+ (name[i].length()-2))
You actually say advance the address stored in p by name[i].length()-2 amount and access that string. If you go past the end of the name array then that is undefined behavior. If not you still haver a std::string which cannot be compared with a char. If you want to check if the string ends with "ca" then you can just use
if (name[i].substr(name[i].size() - 2) == "ca")
You're last loop is doing something quite funky. There's no need to go that far. You can just do something like:
if (name[i][name[i].length - 2] == 'c')
To compare the next to last character with c. And a very similar test to compare the last one with a.
To clarify why what you're doing is not OK, you first get p as a pointer to a string to the current element. Then you do some pointer arithmetic p + (name[i].length - 2), which still results in a pointer to a string. Finally, you dereference this, resulting in a string. Which you can't compare to a char. Moreover, the pointer was to some arbitrary address in memory, so the dereference would produce a string with very bad data in it. Quite arbitrary, one might say. If you tried to work with it you'd break your program
You seem to be working with the string as one would with a C-like string, a char*. The two are not the same, even though they represent the same concepts. A C++ string, usually, has a size field, and a char* pointer inside it, as well as a bunch of other logic to make working with it a char-m.
Because you aren't comparing against a specific char in the string, you're comparing against a string.
Considering the following bit of code:
*(p + (name[i].length() - 2))
This evaluates to a string because you are taking p (a string*) and concatenating a char to it. This means it's still a string (even though it's a one-character string), thus the other side of the equation won't be comparable to it.
What you need here instead is this:
if (name[i][name[i].length() - 2] == 'c')
Since name[i] is already a string, we can just get the char from it using the code above. This does return char, so it's comparable. This also allows you to get rid of the whole string* bit as it is not needed.
First, (i <= sizeof(name)) is wrong, it should be i < sizeof(name) / sizeof(*name). sizeof(array) return the size of array in bytes, you need to divide the size of an array's element to actually get the maximum element count of an array. If you find that complicated then use std::vector:
vector<string> name(10); //a vector of size 10
for (size_t i = 0; i < name.size(); i++) //name.size(), simple
Secondly, you need to keep track of how many strings in your name array. Or you need to check if name[i] == "OK" then break the second loop (similar to the first loop). name[i] after "OK" are invalid.
Thirdly, don't use *(p+ (name[i].length()-2)). If you want the second last character of name[i], you can write it as name[i][name[i].size()-2] or name[i].end()[-2] or end(name[i])[-2]
If you want to check if the word ends in "ca", then you can use substr:
if (name[i].substr(name[i].size() - 2) == "ca")
{
//...
}

C++ how to determine if char is first char in a word

It seems like this should be simple but I can't seem to figure it out. I am trying to write a function that will return true if the character at position pos is the first character of a word. A word it this case is defined as any string of alphanumeric characters.
Here is my latest attempt:
bool wordBeginsAt (const std::string& message, int pos)
{
string temp;
int x;
for (x=pos;isAlphanumeric(message[x]==true);x++)
{
temp[x] = message[x];
}
if (temp[pos]!=0)
{
return false;
}
else
return true;
}
bool isAlphanumeric (char c)
{
return (c >= 'A' && c <= 'Z')
|| (c >= 'a' && c <= 'z')
|| (c >= '0' && c <= '9');
}
By your definition, a character is the first character in a word if it is alphanumeric and either it's the first character in the string or the character before it is not alphanumeric.
Well, isAlphanumeric(message[x]==true) should have been isAlphanumeric(message[x])==true. But your code has other severe issues such as writing out of bounds of temp and the loop logic is all wrong, so I think it is best to start over.
What you need to do is:
Check if the character is alphanumeric
Check that either the previous character isn't, or there is no previous character
No loops or variables are required. The second condition would occur when pos == 0 ; you don't want to check the previous character if you are actually looking at the first character.

strcmpi integer without a cast error

I'm trying to create a program that removes vowels from a string, add them into a vector and then give the user the possibility of having the original code again.
In my code i have this:
char s[20];
And soon after i have this comparison:
for(j=0;j<tam;j++)
{
if(strcmpi(s[j],"a")==1 ||
(strcmpi(s[j],"e")==1 ||
(strcmpi(s[j],"i") ==1||
(strcmpi(s[j],"o") ==1||
(strcmpi(s[j],"u")==1))
{
So if the array is char and the vowels are char(""), why the compiler give me this error?:
[Warning] passing arg 1 of `strcmpi' makes pointer from integer without a cast
EDIT
As someone said the correct is s[j] == 'a', but that result in wrong way. If a put car the result is still car. Don't know why.
if(s[j] == 'a' ||
s[j] == 'A' ||
s[j] == 'e' ||
s[j] == 'E' ||
s[j] == 'i' ||
s[j] == 'I' ||
s[j] == 'o' ||
s[j] == 'O' ||
s[j] == 'u' ||
s[j] == 'U')
{
s[j] = s[j++]; }
Strcmpi is for comparing strings. The first argument to strcmpi is of type char, when it expects a char*.
In order to compare single chars, s[j]=='e' is enough, or tolower(s[j])=='e' if you need it to be case insensitive. You'll need to include ctype.h. for tolower.
The arguments to strcmpi must be strings, but s[j] is just a single character, not a string. You can use == to compare characters directly. To get case-insensitive comparisons, get the lowercase version of the character first and compare it.
for (j = 0; j < tam; j++) {
char lower = tolower(s[j]);
if (lower == 'a' || lower == 'e' || lower == 'i' || lower == 'o' || lower == 'u') {
...
}
}
You don't want to use strcmp or any of its variants.
Because you want to know whether the string contains vowels or not, you may want to use a substring search using strstr.
You use function strcmpi incorrectly. It first parameter has type const char * while you pass an argument of type char. That is the function expects a string while you pass only one character.
Moreover this function is not a standard C/C++ function. So it should not be used.
You could achieve the same result using the following approach
char vowels[] = "aeiou";
//...
if ( strchr( vowels, tolower( s[j] ) )
{
std::cout << s[j] << " is a vowel" << std::endl;
}
You have already been told that strcmpi is not the right way to check single characters. This is an answer to the edit to your question, where you ask about actually stripping the vowels.
If you want to retain the original string, you need extra memory for the string without consonants. You also need two indices, because once you have skipped a vowel in the original string, the indices are out of sync. Here's an example implementation:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
char orig[] = "Jackdaws love my big sphinx of quartz.";
char cons[sizeof(orig)]; // Make new char buffer as big
// as the original
int i, j;
j = 0;
for (i = 0; orig[i]; i++) {
if (strchr("AEIOUaeiou", orig[i]) == NULL) {
cons[j++] = orig[i];
}
}
cons[j] = '\0'; // Terminate consonant string
printf("was: '%s'\n", orig);
printf("is: '%s'\n", cons);
return 0;
}
The expression strchr checks whether a character is in a string. You can use it as a shortcut to spelling out all vowels in explicit comparisons.

Why is my program not reading all of characters in the string?

I need to input a string, if the string is just a whole string and not with spaces, the codes is fine, if the input is a string with spaces, the string only copys the first set of strings and not the whole strings? I'm an noob, please help.
#include <stdio.h>
#include <string.h>
int main() {
char again = 0;
do {
char str[60], s[60];
int i, j = 0;
printf("Enter any string->");
scanf("%s", str);
printf("The string is->%s", str);
for (i = 0; i <= strlen(str); i++) {
if (str[i] == 'a' || str[i] == 'e' || str[i] == 'i' ||
str[i] == 'o' || str[i] == 'u' || str[i] == 'A' ||
str[i] == 'E' || str[i] == 'I' || str[i] == 'O' ||
str[i] == 'U') {
str[i] = ' ';
} else {
s[j++] = str[i];
}
}
s[j] = '\0';
printf("\nThe string without vowel is->%s", s);
NSLog(#"Do you want to enter another string to be edit? (y/n) ");
scanf("%s", &again);
} while (again != 'n');
}
Your code stops reading at a space because that's how scanf works with the %s format. It reads a sequence of non-whitespace characters.
If you're really using C++, then you'd be wise to switch to std::string and std::getline, which will read all input up to the end of the line. Your code doesn't appear to use any C++ features, though, so maybe you're really using C. In that case, consider fgets instead. It will read the whole line, too (up to a specified size, which generally corresponds to the size of your buffer).
This code is a mess.
C++ features like std::string are not used at all.
You're mixing printf/scanf and NSLog for no reason.
Modifying str in the if branch makes no sense, as it won't be read later.
You probably want to use i < strlen(str) instead of <=, or you'll copy that terminating zero character twice.
Your scanf("%s", &again); specifies to read a string, but you only have memory for a character, thus you probably end up writing into some random memory position.
While some of these points are more severe than others, I suggest fixing those issues and see what happens. If you experience unexpected output, then please do give your example input and output as well.
You are allocating an array of 60 chars long (str). You can't expect to read a lot into it. Here are a few tips:
Don't use such buffers, they are dangerous. The C++ library provides you std::string.
Never omit the curly braces {}.
There are an easier way to check for chars than this horribly long if. Hint: std::string::find_first_of