I'm trying to replace multiple words with their "pirate pair", for example:
Normal: "Hello sir, where is the hotel?"
Pirate: "Ahoy matey, whar be th' fleagbag inn?"
This is what I tried before:
#include<iostream>
#include<string>
#include<conio.h>
using namespace std;
void speakPirate(string s);
int main()
{
string phrase;
cout << "Enter the phrase to Pirate-Ize: ";
getline(cin, phrase);
speakPirate(phrase);
_getch();
return 0;
}
void speakPirate(string s)
{
int found;
// list of pirate words
string pirate[12] = { "ahoy", "matey", "proud beauty", "foul blaggart", "scurvy dog", "whar", "be", "th'", "me", "yer", "galley", "fleabag inn" };
// list of normal words
string normal[12] = { "hello", "sir", "madam", "officer", "stranger", "where", "is", "the", "my", "your", "restaurant", "hotel" };
for (int i = 0; i < s.length(); i++)
{
found = s.find(normal[i]);
if (found > -1)
{
string left = s.substr(0, found - 1); // get left of the string
string right = s.substr(found + pirate[i].length(), s.length()); // get right of string
s = left + " " + pirate[i] + " " + right; // add pirate word in place of normal word
}
}
cout << s;
}
But it didn't really work and was very buggy, so I tried using the replace() function instead:
#include<iostream>
#include<string>
#include<conio.h>
using namespace std;
void speakPirate(string s);
int main()
{
string phrase;
cout << "Enter the phrase to Pirate-Ize: ";
getline(cin, phrase);
speakPirate(phrase);
_getch();
return 0;
}
void speakPirate(string s)
{
int found;
// list of pirate words
string pirate[12] = { "ahoy", "matey", "proud beauty", "foul blaggart", "scurvy dog", "whar", "be", "th'", "me", "yer", "galley", "fleabag inn" };
// list of normal words
string normal[12] = { "hello", "sir", "madam", "officer", "stranger", "where", "is", "the", "my", "your", "restaurant", "hotel" };
for (int i = 0; i < s.length(); i++)
{
found = s.find(normal[i]);
if (found > -1)
{
s.replace(found, found + pirate[i].length(), pirate[i]);
}
}
cout << s;
}
I'm not sure why, but this doesn't really work either. I also notice that when I try changing a larger word into a smaller word, some of the original word is leftover, for example:
Enter the phrase to Pirate-Ize: hello
ahoyo
And I just noticed that it sometimes might not even change the word at all, for example:
Enter the phrase to Pirate-Ize: where
where
How come? Could someone please tell me what I need to do or a more effective solution that I could implement? Thanks a lot.
Here you iterate over the length of the text:
for (int i = 0; i < s.length(); i++)
It should be the length of the array of texts, something like
for (int i = 0; i < 12; i++)
However, you should use a std::map to model the mapping between the normal words and their pirate version.
std::map<std::string, std::string> words = {
{"hello", "ahoy"},
// .. and so on
};
for(auto const & kvp : words)
{
// replace kvp.first with kvp.second
}
Marius is correct that the major error is that you need to iterate over the length of the arrays. A different way than mapping would be to use erase() and insert() where you used replace(). replace() does not account for the lengths of the strings being different, but removing a substring and then adding in a new substring will. This can be done as follows
for (int i = 0; i < 12; i++)
{
found = s.find(normal[i]);
// Locate the substring to replace
int pos = s.find( normal[i], found );
if( pos == string::npos ) break;
// Replace by erasing and inserting
s.erase( pos, normal[i].length() );
s.insert( pos, pirate[i] );
}
Related
Here is the code:
string msg;
niceArray = txtReader("chatTest/replaces.txt");
vector<vector<string>>vMaster;
if(vMaster.size() <1){
string arr[] = { "a","A","á","#","à ","â","ã","ÃÃ","€Ã","ƒÃ"};
vector<string> tempA(arr, arr+4);
vMaster.push_back(tempA);//"aAá#à âãÃÀÃÂ"
}
string ex;
while(sstr.good()){
sstr>>ex;
vectorCheck.push_back(ex);
}
for(int e = 0; e < vectorCheck.size(); e=e+1){
//if(e > vectorCheck[e].length()) break;
auto str = vectorCheck[e];
for(int b = 0; b < vMaster.size(); b=b+1){
for(int j=0; vMaster[b].size(); j=j+1){
//int f = str.find(vMaster[b][j]);
if(str.find(vMaster[b][j]) != std::string::npos){
int f = str.find(vMaster[b][j]);
//if(vMaster[b][j].length() > 1){
str.replace(f,2,vMaster[b][0]);
//break;
// }
//
}
}
}
for(int i = 0; i < xingArray.size(); i=i+1){
if(str == xingArray[i]){
vectorCheck[e] = niceArray[rand() % niceArray.size()];
}
}
}
So for each sentence i type i am checking each word and looking if there is any of that string arr characteres in it, if there is i replace it for the vector[0] in this case "a".
The problem is that this line str.find(vMaster[b][j]) != std::string::npos never returns me -1... Even when i type like "c" in finds c in there or "f" or any word and i get an error. The funny stuff is that when i type like "á" that turns into "Ã|" it works and with the "ã" that turns into "ã" it doesnt give me 0 again... I really dont know whats going on... I really tried hard here and if anyone has any opinion i would like to hear thanks.
std::string str ("potato.");
std::string str2 ("ta");
std::size_t found = str.find(str2);
if ( found != std::string::npos)
std::cout << "first 'ta' found at: " << found << '\n';
str.replace( found, 2, "");
I dont think C++ has any single method to find and replace so why not use inbuilt find and then replace.
For example:
void find_and_replace(string& source, string const& find, string const& replace)
{
for(std::string::size_type i = 0; (i = source.find(find, i)) != std::string::npos;)
{
source.replace(i, find.length(), replace);
i += replace.length() - find.length() + 1;
}
}
int main()
{
string text = "potato";
find_and_replace(text, "ta", "");
cout << "After one replacement: " << text << endl;
find_and_replace(text, "te", "");
cout << "After another replacement: " << text << endl;
return 0;
}
I'm a C# programmer that recently wanted to delve into something lower level so last week started learning C++ but have stumbled on something I thought would be fairly simple.
I enter the following string into my program:
"this is a test this test" and would expect the wordStructList to contain a list of 4 words, with occurrences of "test" and "this" set to 2. When debugging however, the string comparison (I've tried .compare and ==) always seems to increasing the value of occurrences no matter whether the comparison is true.
e.g. currentName = "is"
word = "this"
but occurrences is still been incremented.
#include "stdafx.h"
using std::string;
using std::vector;
using std::find;
using std::distance;
struct Word
{
string name;
int occurrences;
};
struct find_word : std::unary_function<Word, bool>
{
string name;
find_word(string name):name(name) { }
bool operator()(Word const& w) const
{
return w.name == name;
}
};
Word GetWordStruct(string name)
{
Word word;
word.name = name;
word.occurrences = 1;
return word;
}
int main(int argc, char argv[])
{
string s;
string delimiter = " ";
vector<string> wordStringList;
getline(std::cin, s);
do
{
wordStringList.push_back(s.substr(0, s.find(delimiter)));
s.erase(0, s.find(delimiter) + delimiter.length());
if (s.find(delimiter) == -1)
{
wordStringList.push_back(s);
s = "";
}
} while (s != "");
vector<Word> wordStructList;
for (int i = 0; i < wordStringList.size(); i++)
{
Word newWord;
vector<Word>::iterator it = find_if(wordStructList.begin(), wordStructList.end(), find_word(wordStringList[i]));
if (it == wordStructList.end())
wordStructList.push_back(GetWordStruct(wordStringList[i]));
else
{
string word(wordStringList[i]);
for (vector<Word>::size_type j = 0; j != wordStructList.size(); ++j)
{
string currentName = wordStructList[j].name;
if(currentName.compare(word) == 0);
wordStructList[j].occurrences++;
}
}
}
return 0;
}
I hope the question makes sense. Anyone shed any light on this? I'm also open to any tips about how to make the code more sensible/readable. Thanks
The problem is the semicolon after this if statement:
if(currentName.compare(word) == 0);
The semicolon terminates the statement, so the next line
wordStructList[j].occurrences++;
is not part of the if statement any more and will always be executed.
Using if and while/do-while, my job is to print following user's inputs (string value) in reverse order.
For example:
input string value : "You are American"
output in reverse order : "American are You"
Is there any way to do this?
I have tried
string a;
cout << "enter a string: ";
getline(cin, a);
a = string ( a.rbegin(), a.rend() );
cout << a << endl;
return 0;
...but this would reverse the order of the words and spelling while spelling is not what I'm going for.
I also should be adding in if and while statements but do not have a clue how.
The algorithm is:
Reverse the whole string
Reverse the individual words
#include<iostream>
#include<algorithm>
using namespace std;
string reverseWords(string a)
{
reverse(a.begin(), a.end());
int s = 0;
int i = 0;
while(i < a.length())
{
if(a[i] == ' ')
{
reverse(a.begin() + s, a.begin() + i);
s = i + 1;
}
i++;
}
if(a[a.length() - 1] != ' ')
{
reverse(a.begin() + s, a.end());
}
return a;
}
Here is a C-based approach that will compile with a C++ compiler, which uses the stack to minimize creation of char * strings. With minimal work, this can be adapted to use C++ classes, as well as trivially replacing the various for loops with a do-while or while block.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE_LENGTH 1000
#define MAX_WORD_LENGTH 80
void rev(char *str)
{
size_t str_length = strlen(str);
int str_idx;
char word_buffer[MAX_WORD_LENGTH] = {0};
int word_buffer_idx = 0;
for (str_idx = str_length - 1; str_idx >= 0; str_idx--)
word_buffer[word_buffer_idx++] = str[str_idx];
memcpy(str, word_buffer, word_buffer_idx);
str[word_buffer_idx] = '\0';
}
int main(int argc, char **argv)
{
char *line = NULL;
size_t line_length;
int line_idx;
char word_buffer[MAX_WORD_LENGTH] = {0};
int word_buffer_idx;
/* set up line buffer - we cast the result of malloc() because we're using C++ */
line = (char *) malloc (MAX_LINE_LENGTH + 1);
if (!line) {
fprintf(stderr, "ERROR: Could not allocate space for line buffer!\n");
return EXIT_FAILURE;
}
/* read in a line of characters from standard input */
getline(&line, &line_length, stdin);
/* replace newline with NUL character to correctly terminate 'line' */
for (line_idx = 0; line_idx < (int) line_length; line_idx++) {
if (line[line_idx] == '\n') {
line[line_idx] = '\0';
line_length = line_idx;
break;
}
}
/* put the reverse of a word into a buffer, else print the reverse of the word buffer if we encounter a space */
for (line_idx = line_length - 1, word_buffer_idx = 0; line_idx >= -1; line_idx--) {
if (line_idx == -1)
word_buffer[word_buffer_idx] = '\0', rev(word_buffer), fprintf(stdout, "%s\n", word_buffer);
else if (line[line_idx] == ' ')
word_buffer[word_buffer_idx] = '\0', rev(word_buffer), fprintf(stdout, "%s ", word_buffer), word_buffer_idx = 0;
else
word_buffer[word_buffer_idx++] = line[line_idx];
}
/* cleanup memory, to avoid leaks */
free(line);
return EXIT_SUCCESS;
}
To compile with a C++ compiler, and then use:
$ g++ -Wall test.c -o test
$ ./test
foo bar baz
baz bar foo
This example unpacks the input string one word at a time,
and builds an output string by concatenating in reverse order.
`
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
string inp_str("I am British");
string out_str("");
string word_str;
istringstream iss( inp_str );
while (iss >> word_str) {
out_str = word_str + " " + out_str;
} // while (my_iss >> my_word)
cout << out_str << endl;
return 0;
} // main
`
This uses exactly one each of if and while.
#include <string>
#include <iostream>
#include <sstream>
void backwards(std::istream& in, std::ostream& out)
{
std::string word;
if (in >> word) // Read the frontmost word
{
backwards(in, out); // Output the rest of the input backwards...
out << word << " "; // ... and output the frontmost word at the back
}
}
int main()
{
std::string line;
while (getline(std::cin, line))
{
std::istringstream input(line);
backwards(input, std::cout);
std::cout << std::endl;
}
}
You might try this solution in getting a vector of string's using the ' ' (single space) character as a delimiter.
The next step would be to iterate over this vector backwards to generate the reverse string.
Here's what it might look like (split is the string splitting function from that post):
Edit 2: If you don't like vectors for whatever reason, you can use arrays (note that pointers can act as arrays). This example allocates a fixed size array on the heap, you may want to change this to say, double the size when the current word amount has reached a certain value.
Solution using an array instead of a vector:
#include <iostream>
#include <string>
using namespace std;
int getWords(string input, string ** output)
{
*output = new string[256]; // Assumes there will be a max of 256 words (can make this more dynamic if you want)
string currentWord;
int currentWordIndex = 0;
for(int i = 0; i <= input.length(); i++)
{
if(i == input.length() || input[i] == ' ') // We've found a space, so we've reached a new word
{
if(currentWord.length() > 0)
{
(*output)[currentWordIndex] = currentWord;
currentWordIndex++;
}
currentWord.clear();
}
else
{
currentWord.push_back(input[i]); // Add this character to the current word
}
}
return currentWordIndex; // returns the number of words
}
int main ()
{
std::string original, reverse;
std::getline(std::cin, original); // Get the input string
string * arrWords;
int size = getWords(original, &arrWords); // pass in the address of the arrWords array
int index = size - 1;
while(index >= 0)
{
reverse.append(arrWords[index]);
reverse.append(" ");
index--;
}
std::cout << reverse << std::endl;
return 0;
}
Edit: Added includes, main function, while loop format
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
// From the post
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems)
{
std::stringstream ss(s);
std::string item;
while(std::getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> elems;
return split(s, delim, elems);
}
int main ()
{
std::string original, reverse;
std::cout << "Input a string: " << std::endl;
std::getline(std::cin, original); // Get the input string
std::vector<std::string> words = split(original, ' ');
std::vector<std::string>::reverse_iterator rit = words.rbegin();
while(rit != words.rend())
{
reverse.append(*rit);
reverse.append(" "); // add a space
rit++;
}
std::cout << reverse << std::endl;
return 0;
}
This code here uses string libraries to detect the blanks in the input stream and rewrite the output sentence accordingly
The algorithm is
1. Get the input stream using getline function to capture the spacecs. Initialize pos1 to zero.
2. Look for the first space in the input stream
3. If no space is found, the input stream is the output
4. Else, get the position of the first blank after pos1, i.e. pos2.
5. Save the sub-string bewteen pos1 and pos2 at the beginning of the output sentence; newSentence.
6. Pos1 is now at the first char after the blank.
7. Repeat 4, 5 and 6 untill no spaces left.
8. Add the last sub-string to at the beginning of the newSentence. –
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string sentence;
string newSentence;
string::size_type pos1;
string::size_type pos2;
string::size_type len;
cout << "This sentence rewrites a sentence backward word by word\n"
"Hello world => world Hello"<<endl;
getline(cin, sentence);
pos1 = 0;
len = sentence.length();
pos2 = sentence.find(' ',pos1);
while (pos2 != string::npos)
{
newSentence = sentence.substr(pos1, pos2-pos1+1) + newSentence;
pos1 = pos2 + 1;
pos2 = sentence.find(' ',pos1);
}
newSentence = sentence.substr(pos1, len-pos1+1) + " " + newSentence;
cout << endl << newSentence <<endl;
return 0;
}
I'm attempting to create a recursive function that outputs a vector of strings that contains all possible word combinations (while retaining order of letters) of a given string. Basically, the foundation of an auto-correct typing program, which produces effects similar that of the iPhone.
vector<string> allPossibleWords(string str, vector<vector<char> > & adjacentKeys)
{
vector<string> words;
cout << str << endl;
if (str.length() == 0)
{
return words;
}
char firstLetter = str[0];
string restOf = str.substr(1, str.length() - 1);
int position = position_in_vector(firstLetter);
for (int i = 0; i < adjacentKeys[position].size(); i++)
{
string temp(1, adjacentKeys[position][i]);
words.push_back(temp);
}
//allPossibleWords(restOf, adjacentKeys);
}
int position_in_vector(char letter)
{
return (letter % 97);
}
For instance, if str is "yp", the output should be a vector containing the values {"yp", "tp", "gp", "hp", "up", "yo", "to", "go", "ho", "uo", "yl", "tl", "gl", "hl", "ul"}. If str is "y", the output should be a vector containing the values {"y", "t", "g", "h", "u"}.
The 26 vectors stored in adjacentKeys contain the letters adjacent to the letter that is stored in the first position of the vector.
a qwsz
b vghjn
c xdfgv
d zserfcx
//and so on
I am stuck with this function, and can't figure out how to recursively build this vector.
(Update: 2130 GMT Sunday: I've significantly changed my answer. I think this works now.)
Here is a complete program. There are other changes I think I would make, but I'm trying to keep to the spirit of your initial solution. It's important to return a single empty word when str.length()==0.
#include <vector>
#include <iostream>
using namespace std;
vector<string> allPossibleWords(string str, vector<vector<char> > & adjacentKeys)
{
vector<string> words;
// cout << "str=" << str << endl;
if (str.length() == 0)
{
words.push_back("");
return words;
}
char firstLetter = str[0];
// cout << "firstLetter=" << firstLetter << endl;
int positionInAdjacentKeys = 0;
while(positionInAdjacentKeys < adjacentKeys.size() && adjacentKeys.at(positionInAdjacentKeys).front() != firstLetter) {
++ positionInAdjacentKeys;
}
vector<char> & adjacent = adjacentKeys.at(positionInAdjacentKeys);
string restOf = str.substr(1, str.length() - 1);
// cout << firstLetter << ":" << restOf << endl;
// int position = position_in_vector(firstLetter);
vector<string> recursiveWords = allPossibleWords(restOf, adjacentKeys);
for (int i = 0; i < adjacent.size(); i++)
{
const string temp(1, adjacent[i]);
// cout << " temp=" << temp << endl;
for(vector<string>::const_iterator i = recursiveWords.begin(); i != recursiveWords.end(); i++)
{
// cout << "new word=" << temp + *i << endl;
words.push_back(temp + *i);
}
}
return words;
}
int main() {
vector<vector<char> > adj;
vector<char> v1;
v1.clear();
v1.push_back('p');
v1.push_back('o');
v1.push_back('l');
adj.push_back(v1);
v1.clear();
v1.push_back('y');
v1.push_back('t');
v1.push_back('g');
v1.push_back('h');
v1.push_back('u');
adj.push_back(v1);
adj.push_back(v1);
vector<string> words = allPossibleWords("yp", adj);
for(vector<string> :: const_iterator i = words.begin(); i != words.end(); i++) {
cout << *i << endl;
}
}
return
Maybe something like this? I haven't tested it because I don't have your adjacentKeys matrix. It can probably be optimised a bit, but I don't think this approach will scale well at all.
I'd suggest attacking the problem from a different angle, perhaps storing your dictionary in some kind of K-ary tree, and having several pointers walking the tree, following branches based on your adjacency matrix. This would stop the generation of invalid words (and subsequent lookups to check validity) as branches would only exist where valid words exist.
using namespace std;
void allPossibleWordsHelper(const string& str,
string::size_type index,
const vector<vector<char> >& adjacentKeys,
vector<string>& results)
{
if (str.length() == 0)
{
return;
}
std::string head = (index > 0) ? str.substr(0, index) : "";
std::string tail = (index < str.length() - 1) ? str.substr(index + 1) : "";
vector<string> possibleHeads;
string::size_type headIndex = (str.length() - index) / 2;
allPossibleWordsHelper(head, headIndex, adjacentKeys, possibleHeads);
vector<string> possibleTails;
allPossibleWordsHelper(tail, index + headIndex, adjacentKeys, possibleTails);
int pos = str[index] - 'a';
vector<string>::const_iterator headi;
vector<string>::const_iterator headi_end = possibleHeads.end();
vector<string>::const_iterator taili;
vector<string>::const_iterator taili_end = possibleTails.end();
vector<char>::const_iterator aki;
vector<char>::const_iterator aki_end = adjacentKeys[pos].end();
for(headi = possibleHeads.begin(); headi != headi_end; ++headi)
{
for (aki = adjacentKeys[pos].begin(); aki != aki_end; ++aki)
{
for (taili = possibleTails.begin(); taili != taili_end; ++taili)
{
string suggestedWord = *headi + *aki + *taili;
results.push_back(suggestedWord);
}
}
}
}
The following program replaces all spaces with %20.the compilation works fine but the program terminates during the runtime.Any help???
#include<iostream>
#include<string>
using namespace std;
void removeSpaces(string url){
int len=url.length();
int i,count=0;
while(i<=len){
if(url[i]==' ')
count++;
i++;
}
int length2=len+(count*2);
string newarr[length2];
for(int j=len-1;j>=0;j--){
if(url[j]==' ')
{
newarr[length2-1]='0';
newarr[length2-2]='2';
newarr[length2-3]='%';
length2=length2-3;
}
else
{
newarr[length2-1]=url[j];
length2=length2-1;
}
}
cout<<"\nThe number of spaces in the url is:"<<count;
cout<<"\nThe replaced url is:"<<newarr;
}
int main(){
string url="http://www.ya h o o.com/";
removeSpaces(url);
}
This is called an "off by one" error.
while(i<=len){
if(url[i]==' ')
I'd also look at std::string::find() and std::string::replace() rather than what you're doing.
EDIT: Since the poster has said this isn't homework:
for (size_t pos = myString.find(' ');
pos != string::npos;
pos = myString.find(' ', pos))
{
myString.replace(pos, 1, "%20");
}
i is not initialized to 0 - this is the danger if using ',' instead of putting each variable on its own line.
As long as you're using string and not char *, why not use the string methods? This is essentially a translation of what you're trying to do (without even using ::find or ::replace):
void removeSpaces(string url)
{
string newUrl;
int count = 0;
for (int j = 0; j < url.length(); ++j)
{
if (url.at(j) == ' ')
{
newUrl.append("%20");
++count;
}
else
newUrl.append(url.at(j));
}
cout << "\nThe number of spaces in the url is:" << count;
cout << "\nThe replaced url is:"<< newUrl;
}
Edit: I see that #Bryan has given the version with ::find and ::replace.
string newarr[length2];
should be:
string newarr;
or
char newarr[length2];
or the more proper way:
char *newarr = new char[length2];
... // code.
delete[] newarr;
string replaceinString(std::string str, std::string tofind, std::string toreplace)
{
size_t position = 0;
for ( position = str.find(tofind); position != std::string::npos; position = str.find(tofind,position) )
{
str.replace(position ,1, toreplace);
}
return(str);
}
use it:
string replace = replaceinString(thisstring, " ", "%20");
string replace2 = replaceinString(thisstring, " ", "-");
string replace3 = replaceinString(thisstring, " ", "+");