how to split a sentence into strings using recursion in c++ - c++

string strings[10];
void split(string s){
int curr=0,start=0,end=0,i=0;
while(i<=len(s)){
if(s[i]==' ' or i == len(s)){
end = i;
string sub;
sub.append(s,start,end-start);
strings[curr] = sub;
start = end + 1;
curr += 1 ;
}
i++;
}
}
for example if the input is " computer laptop screen desktop mouse " then the output string should be:
computer
laptop
screen
desktop
mouse
I have successfully tried using loops but failed using recursion,
can anyone help me solve split() using recursion.
Thank you

This solution assumes you want only words from the string to enter your array and that you want to split on some predetermined string delimiter like <space>" " or <double-dash>"--".
If you need to keep the void function signature, here is one:
void split_rec(string str_array[], size_t arr_index,
string s, string delimiter) {
if (s == "") {
return;
}
size_t str_index = s.find(delimiter);
string word = s.substr(0, str_index);
if (word != "") {
str_array[arr_index++] = word;
}
// find type functions return string::npos if they don't find.
str_index = s.find_first_not_of(delimiter, str_index);
if (str_index == string::npos) {
return;
}
return split_rec(str_array, arr_index, s.substr(str_index), delimiter);
}
But I would recommend returning the size of the array so you communicate what the function is doing more accurately. Like this:
size_t split_rec(string str_array[], size_t arr_index,
string s, string delimiter) {
if (s == "") {
return arr_index;
}
size_t str_index = s.find(delimiter);
string word = s.substr(0, str_index);
if (word != "") {
str_array[arr_index++] = word;
}
str_index = s.find_first_not_of(delimiter, str_index);
if (str_index == string::npos) {
return arr_index;
}
return split_rec(str_array, arr_index, s.substr(str_index), delimiter);
}
Then the call is like this:
string strings[10];
// I left some extra spaces in this string.
string str = " computer laptop screen desktop mouse ";
size_t strings_len = split_rec(strings, 0, str, " ");
cout << "Array is length " << strings_len << endl;
for (size_t i = 0; i < strings_len; i++) {
cout << strings[i] << endl;
}
Array is length 5
computer
laptop
screen
desktop
mouse

Related

Remove the words from a string that start with a certain character

I have to create a function in C++ that would remove all the words from a string that start with a certain character inputted by a user. For example, if I were to have a string "She made up her mind to meet up with him in the morning" and a substring "m", I would like my string to be "She up her to up with him in the".
I believe I would need to find the occurrences of "m", erase it and all the characters after it till the space " ". Would that be the right approach and if so what would be the best methods to use in this case?
With your kind help I have altered and added code a little bit. The first function 'GetNextWord' seems to be working alright, however, there is definitely something wrong with my function, which is supposed to strip the words, as I am not getting any output. Here is the code:
string GetNextWord(string& s, size_t pos) {
string word;
char del = ' ';
int i = 0;
for (int i = 0; i < s.length(); i++) {
if (s[i] != del) {
word += s[i];
}
else break;
}
return word;
}
string StripWordsThatBeginWithLetter(string& s, char c) {
string result;
string word;
size_t pos = 0;
while (true)
{
word = GetNextWord(s, pos);
pos += word.size() + 1;
if (word.size() == 0)
{
break;
}
if (word[0] == c) {
size_t inx = 0;
inx = s.find(word[0]);
s.erase(inx, word.length());
}
else result = s;
}
return result;
}
Here's a hint. I'm guessing this is a homework problem. And I'm probably giving too much away.
std::string GetNextWord(const std::string &s, size_t pos)
{
std::string word;
// your code goes here to return a string that includes all the chars starting from s[pos] until the start of the next word (including trailing whitespace)
// return an empty string if at the end of the string
return word;
}
std::string StripWordsThatBeginWithLetter(const std::string& s, char c)
{
std::string result;
std::string word;
size_t pos = 0;
while (true)
{
word = GetNextWord(s, pos);
pos += word.size();
if (word.size() == 0)
{
break;
}
// your code on processing "word" goes here with respect
// to "c" goes here
}
return result;
}
Simple example in french. You are a gentleman and dont want to say "merde" too often, and so decided not to say any word starting with 'm'.
This program will help you :
"je suis beau merde je sais" becomes "je suis beau je sais"
#include <string>
#include <algorithm>
int main(){
std::string str ("je suis beau merde je le sais");
const auto forbiden_start ((const char) 'm');
std::cout << "initial rude string (word starting with \'" << forbiden_start << "\') : " << str << std::endl;
auto i (str.begin ());
auto wait (false);
std::for_each (str.begin (), str.end (), [&i, &forbiden_start, &wait] (const auto& c) {
if (wait) {
if (c == ' ') {
wait = false; return;
}
}
else {
if (c == forbiden_start) {
wait = true;
}
else *i++ = c;
}
});
if (i != str.end ()) str.erase (i, str.end ());
std::cout << "polite string : " << str << std::endl;
return 0;
}
All is not tested (separator is " "), but it is the idea

C++ find special char and move to the end of a string

I am currently a student taking C++. My issue is that my nested if statement does not find the special chars if they are at the end of the word. From what I can tell, it does not run the function at all. If anyone has any idea what is wrong that will be great!
#include <iostream>
#include <string>
using namespace std;
bool isVowel(char ch);
string rotate(string pStr);
string pigLatinString(string pStr);
bool specialChar(char ch);
int main() {
string str, str2, pigsentence, finalsentence, orgstr, end;
int counter, length, lengtho;
counter = 1;
cout << "Enter a string: ";
getline (cin, str);
cout << endl;
orgstr = str;
//Add in option to move special chars
string::size_type space;
do {
space = str.find(' ', 0); //Finds the space(s)
if(space != string::npos){
str2 = str.substr(0, space); //Finds the word
if(specialChar(str[true])) { //Finds special char
end = str.substr(space - 1); //Stores special char as end
cout << end << endl; //Testing end
str.erase(space - 1); //Erases special car
}
str.erase(0, space + 1); //Erases the word plus the space
pigsentence = pigLatinString(str2); //converst the word
finalsentence = finalsentence + " " + pigsentence + end; //Adds converted word to final string
}else {
length = str.length();
str2 = str.substr(0, length); //Finds the word
if(specialChar(str[true])) { //Finds special char
end = str.substr(space - 1); //Stores special char as end
cout << end << endl; //Testing end
str.erase(space - 1); //Erases special car
}
str.erase(0, length); //Erases the word
pigsentence = pigLatinString(str2); //converst the word
finalsentence = finalsentence + " " + pigsentence + end; //Adds converted word to final string
counter = 0;
}
}while(counter != 0); //Loops until counter == 0
cout << "The pig Laten form of " << orgstr << " is: " << finalsentence << endl;
return 0;
}
The function that lists the specialChars is below
bool specialChar(char ch) {
switch(ch) {
case ',':
case ':':
case ';':
case '.':
case '?':
case '!':
return true;
default:
return false;
}
}
I do have other functions but they are working and just convert a word to piglatin.
your isSpecialChar takes a character as argument so str[index] would be something you could pass but instead you write str[true] which is not correct. If you want to check if there is a specialChar in your string you need to loop through the whole string and check each character.
It seems as if you want to split up a string into words so you could write something like this
char Seperator = ' ';
std::istringstream StrStream(str);
std::string Token;
std::vector<std::string> tokens;
while(std::getline(StrStream, Token, Seperator))
{
tokens.push_back(Token);
}
now that you have the words in a vector you can do whatever what you want
with them like checking for a special char
for (int i = 0; i < tokens.size(); ++i)
{
std::string& s = tokens[i];
for (int j = 0; j < s.length(); ++j)
{
if ( specialChar( s[j] )
{
...do whatever...
}
}
}
You're using true as your array index when passing arguments to the specialChar() function! Surely that isn't what you meant to do. Fix that and you might see some improvement.
Think of the function call broken down a little, like this, to help you keep track of the types:
// takes a char, returns a bool, so....
bool specialChar( char in )
{ ... }
for( int i = 0; i < str.size(); i++ )
{
char aChar = str[i];
// ...pass in a char, and receive a bool!
bool isSpecial = specialChar(aChar);
if( isSpecial )
{
...
}
}
There's generally no harm in writing the code in a way that makes it clearer to you what's going on, when compiled and optimised it will all likely be the same.

Add items to a vector recursively

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);
}
}
}
}

How to find and replace string?

If s is a std::string, then is there a function like the following?
s.replace("text to replace", "new text");
Replace first match
Use a combination of std::string::find and std::string::replace.
Find the first match:
std::string s;
std::string toReplace("text to replace");
size_t pos = s.find(toReplace);
Replace the first match:
s.replace(pos, toReplace.length(), "new text");
A simple function for your convenience:
void replace_first(
std::string& s,
std::string const& toReplace,
std::string const& replaceWith
) {
std::size_t pos = s.find(toReplace);
if (pos == std::string::npos) return;
s.replace(pos, toReplace.length(), replaceWith);
}
Usage:
replace_first(s, "text to replace", "new text");
Demo.
Replace all matches
Define this O(n) method using std::string as a buffer:
void replace_all(
std::string& s,
std::string const& toReplace,
std::string const& replaceWith
) {
std::string buf;
std::size_t pos = 0;
std::size_t prevPos;
// Reserves rough estimate of final size of string.
buf.reserve(s.size());
while (true) {
prevPos = pos;
pos = s.find(toReplace, pos);
if (pos == std::string::npos)
break;
buf.append(s, prevPos, pos - prevPos);
buf += replaceWith;
pos += toReplace.size();
}
buf.append(s, prevPos, s.size() - prevPos);
s.swap(buf);
}
Usage:
replace_all(s, "text to replace", "new text");
Demo.
Boost
Alternatively, use boost::algorithm::replace_all:
#include <boost/algorithm/string.hpp>
using boost::replace_all;
Usage:
replace_all(s, "text to replace", "new text");
Do we really need a Boost library for seemingly such a simple task?
To replace all occurences of a substring use this function:
std::string ReplaceString(std::string subject, const std::string& search,
const std::string& replace) {
size_t pos = 0;
while ((pos = subject.find(search, pos)) != std::string::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
return subject;
}
If you need performance, here is an optimized function that modifies the input string, it does not create a copy of the string:
void ReplaceStringInPlace(std::string& subject, const std::string& search,
const std::string& replace) {
size_t pos = 0;
while ((pos = subject.find(search, pos)) != std::string::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
}
Tests:
std::string input = "abc abc def";
std::cout << "Input string: " << input << std::endl;
std::cout << "ReplaceString() return value: "
<< ReplaceString(input, "bc", "!!") << std::endl;
std::cout << "ReplaceString() input string not modified: "
<< input << std::endl;
ReplaceStringInPlace(input, "bc", "??");
std::cout << "ReplaceStringInPlace() input string modified: "
<< input << std::endl;
Output:
Input string: abc abc def
ReplaceString() return value: a!! a!! def
ReplaceString() input string not modified: abc abc def
ReplaceStringInPlace() input string modified: a?? a?? def
Yes: replace_all is one of the boost string algorithms:
Although it's not a standard library, it has a few things on the standard library:
More natural notation based on ranges rather than iterator pairs. This is nice because you can nest string manipulations (e.g., replace_all nested inside a trim). That's a bit more involved for the standard library functions.
Completeness. This isn't hard to be 'better' at; the standard library is fairly spartan. For example, the boost string algorithms give you explicit control over how string manipulations are performed (i.e., in place or through a copy).
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string str("one three two four");
string str2("three");
str.replace(str.find(str2),str2.length(),"five");
cout << str << endl;
return 0;
}
Output
one five two four
like some say boost::replace_all
here a dummy example:
#include <boost/algorithm/string/replace.hpp>
std::string path("file.gz");
boost::replace_all(path, ".gz", ".zip");
Not exactly that, but std::string has many replace overloaded functions.
Go through this link to see explanation of each, with examples as to how they're used.
Also, there are several versions of string::find functions (listed below) which you can use in conjunction with string::replace.
find
rfind
find_first_of
find_last_of
find_first_not_of
find_last_not_of
Also, note that there are several versions of replace functions available from <algorithm> which you can also use (instead of string::replace):
replace
replace_if
replace_copy
replace_copy_if
// replaced text will be in buffer.
void Replace(char* buffer, const char* source, const char* oldStr, const char* newStr)
{
if(buffer==NULL || source == NULL || oldStr == NULL || newStr == NULL) return;
int slen = strlen(source);
int olen = strlen(oldStr);
int nlen = strlen(newStr);
if(olen>slen) return;
int ix=0;
for(int i=0;i<slen;i++)
{
if(oldStr[0] == source[i])
{
bool found = true;
for(int j=1;j<olen;j++)
{
if(source[i+j]!=oldStr[j])
{
found = false;
break;
}
}
if(found)
{
for(int j=0;j<nlen;j++)
buffer[ix++] = newStr[j];
i+=(olen-1);
}
else
{
buffer[ix++] = source[i];
}
}
else
{
buffer[ix++] = source[i];
}
}
}
Here's the version I ended up writing that replaces all instances of the target string in a given string. Works on any string type.
template <typename T, typename U>
T &replace (
T &str,
const U &from,
const U &to)
{
size_t pos;
size_t offset = 0;
const size_t increment = to.size();
while ((pos = str.find(from, offset)) != T::npos)
{
str.replace(pos, from.size(), to);
offset = pos + increment;
}
return str;
}
Example:
auto foo = "this is a test"s;
replace(foo, "is"s, "wis"s);
cout << foo;
Output:
thwis wis a test
Note that even if the search string appears in the replacement string, this works correctly.
void replace(char *str, char *strFnd, char *strRep)
{
for (int i = 0; i < strlen(str); i++)
{
int npos = -1, j, k;
if (str[i] == strFnd[0])
{
for (j = 1, k = i+1; j < strlen(strFnd); j++)
if (str[k++] != strFnd[j])
break;
npos = i;
}
if (npos != -1)
for (j = 0, k = npos; j < strlen(strRep); j++)
str[k++] = strRep[j];
}
}
int main()
{
char pst1[] = "There is a wrong message";
char pfnd[] = "wrong";
char prep[] = "right";
cout << "\nintial:" << pst1;
replace(pst1, pfnd, prep);
cout << "\nfinal : " << pst1;
return 0;
}
void replaceAll(std::string & data, const std::string &toSearch, const std::string &replaceStr)
{
// Get the first occurrence
size_t pos = data.find(toSearch);
// Repeat till end is reached
while( pos != std::string::npos)
{
// Replace this occurrence of Sub String
data.replace(pos, toSearch.size(), replaceStr);
// Get the next occurrence from the current position
pos =data.find(toSearch, pos + replaceStr.size());
}
}
More CPP utilities: https://github.com/Heyshubham/CPP-Utitlities/blob/master/src/MEString.cpp#L60
is there a function like the following?
One other(in addition to using boost and other methods given in different answers) possible way of doing this is using std::regex_replace as shown below:
std::string s{"my name is my name and not my name mysometext myto"}; //this is the original line
std::string replaceThis = "my";
std::string replaceWith = "your";
std::regex pattern("\\b" + replaceThis + "\\b");
std::string replacedLine = std::regex_replace(s, pattern, replaceWith);
std::cout<<replacedLine<<std::endl;

replacing space with %20

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, " ", "+");