c++: string.replace inserting too many characters - c++

I'm trying to step through a given string with a for loop, replacing one character per iteration with a character from a vector[char].
Problem is that the replace inserts the entire vector-k instead of the character at place k and I cannot figure out what I've done wrong.
Any and all help is appreciated.
(alphabet is a const string a-z, FirstWord is the given string).
vector<char> VectorAlphabet;
for (int i=0; i<alphabet.length(); ++i)
{
VectorAlphabet.push_back(alphabet.at(i));
}
for (int i = 0; i < FirstWord.length(); ++i )
{
for (int k = 0; k < VectorAlphabet.size(); ++k)
{
string TempWord = FirstWord;
TempWord.replace(i, 1, &VectorAlphabet[k]);
if (CheckForValidWord(TempWord, WordSet))
{
if(CheckForDuplicateChain(TempWord, DuplicateWordSet))
{
DuplicateWordSet.insert(TempWord);
stack<string> TempStack = WordStack;
TempStack.push(TempWord);
WordQueue.push(TempStack);
}
}
}
}
e.g TempWord = tempword, then after TempWord.replace() on the first iteration it is abcde...zempWord. and not aempword. On the second to last iteration of the second for loop it is yzempword.
What have I missed?

Problem solved, thanks to Dieter Lücking.
Looking closer at the string.replace reference, I see that I tried to use a replace which takes strings as the input, and then the vector[char] is interpreted as a c-string, starting from the k-position.
By using the fill-version of replace the vector position is correctly used as a char instead.
New code is:
for (int i = 0; i < FirstWord.length(); ++i )
{
for (int k = 0; k < VectorAlphabet.size(); ++k)
{
string TempWord = WordStack.top();
// Change:
TempWord.replace(i, 1, 1, VectorAlphabet[k]);
if (CheckForValidWord(TempWord, WordSet))
{
if(CheckForDuplicateChain(TempWord, DuplicateWordSet))
{
DuplicateWordSet.insert(TempWord);
stack<string> TempStack = WordStack;
TempStack.push(TempWord);
WordQueue.push(TempStack);
}
}
}
}

Related

Adding a space before a character in a string C++ insert function

I am attempting to add space before a character in a string by using the insert function.
Can someone kindly explain why the following code does not work ?
for(int i = 0; i < line.length(); i++)
{
if(line[i+1] == '=')
{
line.insert(i, " ");
}
}
If you want to insert before = you can get the index of = directly and not the index of char followed by =. This could lead to out of bounds access.
Also, when you insert the space you extend your string by 1, that's ok but only if you also adjust the counter i, otherwise it will insert again and again and again before = resulting in infinite loop. Adjust your code in this manner:
for (int i = 0; i < line.length(); i++)
{
if (line[i] == '=')
{
line.insert(i++, " ");
}
}
The code seems fine except for one little detail:
Imagine you have a string with "test=something". When you iterate it, when i is 3 you will find the next character is an equals, so you put a space into it. Next iteration i will be 4, but you just added a space, so at i equals 5 there's the same equals sign. So you put another space and so on. TO fix this youy can try:
std::string line = "test=something";
for (int i = 0; i < line.length(); i++)
{
if (line[i + 1] == '=')
{
i++;
line.insert(i, " ");
}
}

Non-Space delimited text file to 2D vector

I've got a file that can be of any size and is a series of char values without any spaces between (except a blank space is treated as a blank cell of a grid).
xxxxxxx
xx xx
xxyyyxx
After some great help I've gone with the method to use a vector<vector<char> > however I cannot seem to populate it.
void readCourse(istream& fin) {
// using 3 and 7 to match example shown above
vector<vector<char> > data(3, vector<char>(7));
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 7; j++) {
fin.get(data[i][j]); // I believe the problem exists here
} // Does the .get() method work here?
} // Or does it need to be .push_back()?
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 7; j++) {
cout << data[i][j];
}
}
}
Is my method for populating my 2D vector valid? If not, can you please point me in the right direction?
I'd keep it simple and efficient with a single vector<char>:
vector<char> readCourse(istream& fin) {
vector<char> course(3*(7+2)); // 3x7 plus newlines
fin.read(course.data(), course.size());
course.resize(fin.gcount());
auto end = remove(course.begin(), course.end(), '\n');
end = remove(course.begin(), end, '\r');
course.erase(end, course.end()); // purge all \n and \r
return course;
}
That's a single input operation to get all the data, followed by removing the characters you don't need. You can then access the result in a 2D way like this:
course.at(x + y*7) // assuming width 7
That may seem a bit inconvenient, but it is efficient and compact--the overhead is always three pointers and a single heap allocation, instead of being proportional to the number of rows.
Solution I ended up using after ADT implementation:
void readCourse(std::istream& fin) {
std::vector<std::string> level
std::string line;
while(std::getline(fin, line) {
level.push_back(line);
}
for (std::size_t i = 0; i < 3; i++) {
for (std::size_t j = 0; j < 7; j++) {
std::cout << data[i][j];
}
std::cout << std::endl;
}
}

Using strlen to strikeout specified words in string

Using the following function, I am able to pass in two strings (char *hide, char *phrase). The *phrase is the overall string and * hide is what words (can be repeated) have to be censored by replacing all letters in the word with '*'. It currently works so that it goes on to find the first letter of the *hide, then the second letter of the *hide word despite it not being next to each other in the string eg.
*phrase = 'hello my name is'
*hide = 'lame'
result = 'he*lo my n*** is'
{
int i, j=0;
int lengthPhrase = strlen(phrase);
int lengthCensor = strlen(hide);
for (i = 0; i < lengthPhrase; i++) {
if (phrase[i] == hide[j]) {
phrase[i] = '*';
j++;
}
}
}
Where is the issue so that it works correctly by striking out the whole words??
Thank you for your time.
Since I don't seem to understand your question, I thought of making a function for you to see if this is what you're looking for:
string phrase = "hello my name is"
string hide = "lame"
//strikeout function
void strikeout(string phrase, string hide)
{
for (int i = 0; i < hide.size(); i++)
{
for (int j = 0; j < phrase.size(); j++)
{
if (hide[i] == phrase[j])
{
phrase[j] = '*';
}
}
}
cout << phrase << endl;
}
Output based on your testcase: "h***o *y n*** is"

String matching algorithm trying to correct it

I'm trying to do string matching algorithm a brute force method. but The algorithm is not working correctly, I get an out of bound index error.
here is my algorithm
int main() {
string s = "NOBODY_NOTICED_HIM";
string pattern="NOT";
int index = 0;
for (int i = 0; i < s.size();)
{
for (int j = 0; j < pattern.size();)
{
if(s[index] == pattern[j])
{
j++;
i++;
}
else
{
index = i;
j = 0;
}
}
}
cout<<index<<endl;
return 0;
}
FIXED VERSION
I fixed the out of bound exception. I don't know if the algorithm will work with different strings
int main() {
string s = "NOBODY_NOTICED_HIM";
string pattern="NOT";
int index = 0;
int i = 0;
while( i < s.size())
{
i++;
for (int j = 0; j < pattern.size();)
{
if(s[index] == pattern[j])
{
index++;
j++;
cout<<"i is " <<i << " j is "<<j <<endl;
}
else
{
index = i;
break;
}
}
}
cout<<i<<endl;
return 0;
}
Because the inner for loop has a condition to loop while j is less than pattern.size() but you are also incrementing i inside the body. When i goes out of bounds of s.size() then index also goes out of bounds and you'd get an OutOfBounds error.
The brute force method has to test the pattern with every possible subsequence. The main condition is the length, which has to be the same. All subsequence from s are:
['NOB', 'OBO', 'BOD', 'ODY', 'DY_', 'Y_N', 'NO', 'NOT', 'OTI', 'TIC',
'ICE', 'CED', 'ED', 'D_H', '_HI', 'HIM']
There are many ways to do it, you can do it char by char, or by using string operations like taking a substring. Both are nice excercises for learning.
Starting at zero in the s string you take the first three chars, compare to the pattern, and if equal you give the answer. Otherwise you move on to the char starting at one, etc.

Convert a string into a char array

New to C++ and So here is part of a project I'm working on, taking a string and printing the most commonly used number along with how many times it was used. i thought this was right, but for some reason my char array wont be read in. any tips or suggestions on how to fix?
#include <string>
#include <iostream>
using namespace std;
char getMostFreqLetter(string ss);
int main() {
string s; //initilizing a variable for string s
s = ("What is the most common letter in this string "); // giving s a string
getMostFreqLetter(s); // caling the function to print out the most freq Letter
return 0;
}
char getMostFreqLetter(string ss) {
int max, index, i = 0;
int array[255] = {0};
char letters[];
// convert all letters to lowercase to make counting letters non case sensative
for (int i = 0; i < ss.length(); i ++){
ss[i] = tolower(ss[i]);
}
//read each letter into
for (int i = 0; i < ss.length(); i ++){
++array[letters[i]];
}
//
max = array[0];
index = 0;
for (int i = 0; i < ss.length(); i ++){
if( array[i] > max)
{
max = array[i];
index = i;
}
}
return 0;
}
If you are not considering white space as letter.
Then more efficient way could have been
vector<int> count(26,0);
for (int i = 0; i < s.length(); i++) {
int range = to_lower(s[i])-'a';
if ( range >= 0 && range < 26)
count[range]++;
}
// Now you can do fix the max while iterating over count;
Use string::c_str().
It converts a string to a character array.
You have a few errors in your code.
Firstly, the array of chars letters is completely unused. You should disregard it and iterate over the string ss instead which is what I think you intended to do.
This would change your second for loop from ++array[letters[i]]; to ++array[ss[i]];.
Secondly, your last for loop is buggy. You are using i as the index to look for the frequency in array whereas you need to use the ascii value of the character (ss[i]) instead. Here is a fixed version with comments:
index = ss[0];
max = array[index];
for (int i = 0; i < ss.length(); i ++){
if(!isspace(ss[i]) && array[ss[i]] > max)
{
max = array[ss[i]]; // you intended to use the ascii values of the characters in s to mark their place in array. In you code, you use i which is the just the index of the character in s as opposed to the ascii value of that character. Hence you need to use array[ss[i]].
index = ss[i];
}
}
return index;
Once you make the above changes you get the following output when run on your string:
Most freq character: t