C++ Counting words in a file between two words - c++

I am currently trying to count the number of words in a file. After this, I plan to make it count the words between two words in the file. For example. My file may contain. "Hello my name is James". I want to count the words, so 5. And then I would like to count the number of words between "Hello" and "James", so the answer would be 3. I am having trouble with accomplishing both tasks.
Mainly due to not being exactly sure how to structure my code.
Any help on here would be greatly appreciated. The code I am currently using is using spaces to count the words.
Here is my code:
readwords.cpp
string ReadWords::getNextWord()
{
bool pWord = false;
char c;
while((c = wordfile.get()) !=EOF)
{
if (!(isspace(c)))
{
nextword.append(1, c);
}
return nextword;
}
}
bool ReadWords::isNextWord()
{
if(!wordfile.eof())
{
return true;
}
else
{
return false;
}
}
main.cpp
main()
{
int count = 0;
ReadWords rw("hamlet.txt");
while(rw.isNextWord()){
rw.getNextWord();
count++;
}
cout << count;
rw.close();
}
What it does at the moment is counts the number of characters. I'm sure its just a simple fix and something silly that I'm missing. But I've been trying for long enough to go searching for some help.
Any help is greatly appreciated. :)

Rather than parse the file character-by-character, you can simply use istream::operator<<() to read whitespace-separated words. << returns the stream, which evaluates to true as a bool when the stream can still be read from.
vector<string> words;
string word;
while (wordfile >> word)
words.push_back(word);
There is a common formulation of this using the <iterator> and <algorithm> utilities, which is more verbose, but can be composed with other iterator algorithms:
istream_iterator<string> input(wordfile), end;
copy(input, end, back_inserter(words));
Then you have the number of words and can do with them whatever you like:
words.size()
If you want to find "Hello" and "James", use find() from the <algorithm> header to get iterators to their positions:
// Find "Hello" anywhere in 'words'.
const auto hello = find(words.begin(), words.end(), "Hello");
// Find "James" anywhere after 'hello' in 'words'.
const auto james = find(hello, words.end(), "James");
If they’re not in the vector, find() will return words.end(); ignoring error checking for the purpose of illustration, you can count the number of words between them by taking their difference, adjusting for the inclusion of "Hello" in the range:
const auto count = james - (hello + 1);
You can use operator-() here because std::vector::iterator is a “random-access iterator”. More generally, you could use std::distance() from <iterator>:
const auto count = distance(hello, james) - 1;
Which has the advantage of being more descriptive of what you’re actually doing. Also, for future reference, this kind of code:
bool f() {
if (x) {
return true;
} else {
return false;
}
}
Can be simplified to just:
bool f() {
return x;
}
Since x is already being converted to bool for the if.

To count:
std::ifstream infile("hamlet.txt");
std::size_t count = 0;
for (std::string word; infile >> word; ++count) { }
To count only between start and stop:
std::ifstream infile("hamlet.txt");
std::size_t count = 0;
bool active = false;
for (std::string word; infile >> word; )
{
if (!active && word == "Hello") { active = true; }
if (!active) continue;
if (word == "James") break;
++count;
}

I think "return nextword;" should instead be "else return nextword;" or else you are returning from the function getNextWord every time, no matter what the char is.
string ReadWords::getNextWord()
{
bool pWord = false;
char c;
while((c = wordfile.get()) !=EOF)
{
if (!(isspace(c)))
{
nextword.append(1, c);
}
else return nextword;//only returns on a space
}
}

To count all words:
std::ifstream f("hamlet.txt");
std::cout << std::distance (std::istream_iterator<std::string>(f),
std::istream_iterator<std::string>()) << '\n';
To count between two words:
std::ifstream f("hamlet.txt");
std::istream_iterator<std::string> it(f), end;
int count = 0;
while (std::find(it, end, "Hello") != end)
while (++it != end && *it != "James")
++count;
std::cout << count;

Try this:
below the line
nextword.append(1, c);
add
continue;

Related

Trying to find isogram in a string c++

I am trying to write a code that has two functions: one that determines whether the string is an isogram or not and another one to print the outcome (true or false) to the console (for the purpose of solving the task).
Some of the things are not working correctly though. And I wonder where I need to improve the code (probably all over...). I would appreciate any advice :)
#include <iostream>
#include<string>
#include<bits/stdc++.h>
#include<iomanip>
bool find_Isogram (std::string str)
{
std::sort(str.begin(), str.end()); //sorted the string for the for loop (e.g. eHllo)
int length = str.length();
for (int i = 0; i < length; i++)
{
if (str.at(i) == str.at(i+1))
{
return false;
break;
}
else
{
return true;
}
}
}
void print_result()
{
std::string str;
if (!find_Isogram (str))
{
std::cout << "false" << std::endl;
}
else
{
std::cout << "true" << std::endl;
}
}
int main()
{
find_Isogram ("gdtub");
print_result();
return 0;
};
````````````````````````````````````````````````````
There are some problems here:
1) You always check an empty string:
print_result will just check an empty string, but it's redundant anyway.
void print_result()
{
std::string str; // empty string
if (!find_Isogram (str)) // finding isogram on empty string
{
std::cout << "false" << std::endl;
}
...
}
It can be simplified with std::boolalpha that allows you to print a bool as "true" or "false" (instead of 1 or 0). main would become
int main()
{
std::cout << std::boolalpha << find_Isogram ("gdtub"); // prints true or false
};
2) Isogram check always ends after first character
Take a look at the condition in find_Isogram. It has a return-statement in the if and else, so you always return after checking the first character.
The idea to detect duplicate characters this way is correct (except for the off-by-one-error already mentioned by others). But you want to return true; only after checking all of the characters, e.g. outside the loop:
bool find_Isogram (std::string str)
{
std::sort(str.begin(), str.end()); //sorted the string for the for loop (e.g. eHllo)
int length = str.length();
for (int i = 0; i < length - 1; i++)
{
if (str.at(i) == str.at(i+1))
{
return false; // whoops duplicate char, stop here
}
}
return true; // no duplicates found, it's an isogram
}
For some further C++-magic, you could simplify it even more with standard library functions :D
bool find_Isogram (std::string str)
{
std::sort(str.begin(), str.end());
return std::unique(str.begin(), str.end()) == str.end();
}
The condition where you check the consecutive characters for equality is wrong. It will yield true for strings like ABAB. You instead need to use a map with count of each character that has appeared.
Something like:
std::map<char, int> map_of_chars;
for(int i = 0; i < length; i++) {
map_of_chars[str.at(i)] = map_of_chars[str.at(i)] + 1;
}
If any value in the map is more than 1 return false;
Another implementation would be using the return value of std::unique():
std::sort(str.begin(), str.end());
auto intial_size = str.size();
std::unique(str.begin(), str.end());
if(str.size() == initial_size) {
/is an isogram
}
else {
//is not an isogram
}

Beginner C++ - String Comparison

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.

How to search words that contain more than three of the same letter through out the entire word

For some reason this code is printing out all the words in my list, while I want it to just print out words with more than three z's
I've managed to solve the code, below its searching for words that that have "zz" in them, an example buzz or blizzard. My main goal is to search for words that three z's through out the entire word an example off the top of my head would be zblizzard or something.
Word* Dictionary::findzs()
{
int wordIndex = 0;
cout << "List : " << endl;
while (wordIndex < MAX_WORDS) {
string word1 = myWords[wordIndex]->word;
wordIndex++;
if (word1.find("zz") != std::string::npos){
cout << word1 << endl;
}
}
return 0;
}
update:
bool has_3_zs(const std::string& s)
{
return std::count(std::begin(s), std::end(s), 'z') >= 3;
}
void Dictionary::has3zs()
{
int wordIndex = 0;
string word = myWords[wordIndex]->word;
while (wordIndex < MAX_WORDS) {
for (auto& s : { word })
{
if (has_3_zs(s))
{
std::cout << s << '\n';
}
}
}
}
There are several problems:
string::find_first_of() is not the right function to use. It searches the string for the first character that matches any of the characters specified in its argument. In other words, your code does indeed look for a single letter z (since that's the only distinct letter that appears in subString). If you wish to find three z's in a row, use string::find() instead. If you wish to find three z's anywhere in the string, use std::count().
Your are not checking the return value correctly. You are implicitly comparing the return value to zero, whereas you need to be comparing against string::npos.
The wordIndex++ is misplaced.
return myWords[wordIndex] looks like out-of-bounds access, potentially resulting in undefined behaviour.
I get it now. You want to match strings that contain a least 3 'z' characters anywhere.
Use std::count. This example:
#include <algorithm> // std::count
#include <iostream> // std::cout
#include <iterator> // std::begin, std::end
#include <string> // std::string
// This is the function you care about.
// It returns `true` if the string has at least 3 'z's.
bool has_3_zs (const std::string& s)
{
return std::count(std::begin(s), std::end(s), 'z') >= 3;
}
// This is just a test case. Ignore the way I write my loop.
int main()
{
for (auto& s : {"Hello", "zWorzldz", "Another", "zStzzring"} )
{
if (has_3_zs(s))
{
std::cout << s << '\n';
}
}
}
prints:
zWorzldz
zStzzring
Edit:
Ok, I've written an example a bit more like yours. My loop is written roughly the same way as yours (which in my opinion is not the best, but I don't want to add further confusion).
// This is the function you care about.
// It returns `true` if the string has at least 3 'z's.
bool has_3_zs (const std::string& s)
{
return std::count(std::begin(s), std::end(s), 'z') >= 3;
}
struct SomeTypeWithAWord
{
std::string word; // The bit you care about
// Allow me to easily make these for my example
SomeTypeWithAWord(char const * c) : word(c) {}
};
// This will contain the words.
// Don't worry about how I fill it up,
// I've just written it the shortest way I know how.
std::vector<SomeTypeWithAWord> myWords
{"Hello", "zWorzldz", "Another", "zStzzring"};
// This is the function you are trying to write.
// It loops over `myWords` and prints any with 3 or more 'z's.
void findzs()
{
std::cout << "List : \n";
std::vector<SomeTypeWithAWord>::size_type wordIndex = 0;
while (wordIndex < myWords.size()) // Loop over all the words
{
const std::string& testWord = myWords[wordIndex].word;
if (has_3_zs(testWord)) // Test each individual word
{
std::cout << testWord << '\n'; // Print it
}
++wordIndex;
}
}
int main()
{
findzs();
}
EDIT- BoB TFish is the simpler, hence better solution.
You may use find_first_of 3 times to see if you have (at least) 3 z's spread throughout the word.
Try something like this:
Word* Dictionary::findzs()
{
int wordIndex = 0;
cout << "List : " << endl;
size_t where;
int i;
string subString = "z"; // or "zZ" if you want uppercase as well
while (wordIndex < MAX_WORDS) {
string word1 = myWords[wordIndex]->word;
where = 0;
for (i = 0 ; i < 3 ; i++)
{
where = word1.find_first_of(substring, where);
if (where == string::npos)
break;
where++; // fix...
}
if (i == 3)
{
cout << word1 << endl;
}
wordIndex++;
}
//return myWords[wordIndex]; - this will try to return myWords[MAX_WORDS] which is probably outside array bounds
return NULL; // or whatever else you see fit
}

set<string>: how to list not strings starting with given string and ending with `/`?

for example we have in our set:
bin/obj/Debug/CloudServerPrototype/ra.write.1.tlog
bin/obj/Debug/CloudServerPrototype/rc.write.1.tlog
bin/obj/Debug/vc100.idb
bin/obj/Debug/vc100.pdb
So this is what I tried based on this grate answer:
#include <iostream>
#include <algorithm>
#include <set>
#include <string>
#include <iterator>
using namespace std;
struct get_pertinent_part
{
const std::string given_string;
get_pertinent_part(const std::string& s)
:given_string(s)
{
}
std::string operator()(const std::string& s)
{
std::string::size_type first = 0;
if (s.find(given_string) == 0)
{
first = given_string.length() + 1;
}
std::string::size_type count = std::string::npos;
std::string::size_type pos = s.find_last_of("/");
if (pos != std::string::npos && pos > first)
{
count = pos + 1 - first;
}
return s.substr(first, count);
}
};
void directory_listning_without_directories_demo()
{
set<string> output;
set<string> demo_set;
demo_set.insert("file1");
demo_set.insert("file2");
demo_set.insert("folder/file1");
demo_set.insert("folder/file2");
demo_set.insert("folder/folder/file1");
demo_set.insert("folder/folder/file2");
demo_set.insert("bin/obj/Debug/CloudServerPrototype/ra.write.1.tlog");
demo_set.insert("bin/obj/Debug/CloudServerPrototype/rc.write.1.tlog");
demo_set.insert("bin/obj/Debug/vc100.idb");
demo_set.insert("bin/obj/Debug/vc100.pdb");
std::transform(demo_set.begin(),
demo_set.end(),
std::inserter(output, output.end()),
get_pertinent_part("bin/obj/Debug/"));
std::copy(output.begin(),
output.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
}
int main()
{
directory_listning_without_directories_demo();
cin.get();
return 0;
}
This outputs:
CloudServerPrototype/
file1
file2
folder/
folder/folder/
vc100.idb
vc100.pdb
and we are given with bin/obj/Debug/string. We want to cout:
vc100.idb
vc100.pdb
CloudServerPrototype/
How to do such thing?
Quick example of what you want to do.
String.find(): http://www.cplusplus.com/reference/string/string/find/
String.subStr(): http://www.cplusplus.com/reference/string/string/substr/
string str = "bin/obj/Debug/vc100.pdb";
string checkString ("bin/obj/Debug");
// Check if string starts with the check string
if (str.find(checkString) == 0){
// Check if last letter if a "/"
if(str.substr(str.length()-1,1) == "/"){
// Output strating at the end of the check string and for
// the differnce in the strings.
cout << str.substr(checkString.length(), (str.length() - checkString.length()) ) << endl;
}
}
It's not clear with which part of the problem you are stuck, so here is a starter for you.
To get the parts of the strings between "given string" and the final '/' (where present):
std::string get_pertinent_part(const std::string& s)
{
std::string::size_type first = 0;
if (s.find(given_string) == 0)
{
first = given_string.length() + 1;
}
std::string::size_type count = std::string::npos;
std::string::size_type pos = s.find_last_of("/");
if (pos != std::string::npos && pos > first)
{
count = pos + 1 - first;
}
return s.substr(first, count);
}
To insert these parts into a new set (output) to guarantee uniqueness you can use the following:
std::transform(your_set.begin(),
your_set.end(),
std::inserter(output, output.end()),
get_pertinent_part);
You may wish to pass given_string into get_pertinent_part(), in which case you'll need to convert it to a functor:
struct get_pertinent_part
{
const std::string given_string;
get_pertinent_part(const std::string& s)
:given_string(s)
{
}
std::string operator()(const std::string& s)
{
std::string::size_type first = 0;
//
// ...same code as before...
//
return s.substr(first, count);
}
};
You can then call it this way:
std::transform(your_set.begin(),
your_set.end(),
std::inserter(output, output.end()),
get_pertinent_part("bin/obj/Debug"));
To output the new set:
std::copy(output.begin(),
output.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
Sorting the results is left as an exercise.
The easiest way I can think of, using the standard C functions, would be:
char * string1 = "bin/obj/Debug"
char * string2 = "bin/obj/Debug/CloudServerPrototype/rc.write.1.tlog"
char result[64];
// the above code is just to bring the strings into this example
char * position = strstr(string1, string2);
int substringLength;
if(position != NULL){
position += strlen(string2);
substringLength = strchr(position, '/') - position;
strncpy(result, position, substringLength);
}else{
strcpy(result, string1); // this case is for when your first string is not found
}
cout << result;
The first thing that occurs, is finding the substring, string1, in the string we are analyzing, being string2. Once we found the starting point, and assuming it was there at all, we add the length of that substring to that starting point using pointer arithmatic, and then find the resulting string's length by subtracting the starting position from the ending position, which is found with strchr(position, '/'). Then we simply copy that substring into a buffer and it's there to print with cout.
I am sure there is a fancy way of doing this with std::string, but I'll leave that to anyone who can better explain c++ strings, I never did manage to get comfortable with them, haha

Write a recursive function that reverses the input string

I've been reading the book C++ For Everyone and one of the exercises said to write a function string reverse(string str) where the return value is the reverse of str.
Can somebody write some basic code and explain it to me? I've been staring at this question since yesterday and can't figure it out. The furthest I've gotten is having the function return the first letter of str (Which I still don't know how it happened)
This is as far as I got (An hour after posting this question):
string reverse(string str)
{
string word = "";
if (str.length() <= 1)
{
return str;
}
else
{
string str_copy = str;
int n = str_copy.length() - 1;
string last_letter = str_copy.substr(n, 1);
str_copy = str_copy.substr(0, n);
word += reverse(str_copy);
return str_copy;
}
return word;
}
If I enter "Wolf", it returns Wol. Somebody help me out here
If I return word instead of return str_copy then I get a w
If I return last_letter then I get an l
I'll instead explain the recursive algorithm itself. Take the example "input" which should produce "tupni". You can reverse the string recursively by
If the string is empty or a single character, return it unchanged.
Otherwise,
Remove the first character.
Reverse the remaining string.
Add the first character above to the reversed string.
Return the new string.
Try this one
string reverse(string &s)
{
if( s.length() == 0 ) // end condtion to stop recursion
return "";
string last(1,s[s.length()-1]); // create string with last character
string reversed = reverse(s.substr(0,s.length()-1));
return last+reversed; // Make he last character first
}
A recursive function must have the following properties
It must call itself again
It must have a condition when the recursion ends. Otherwise you have a function which
will cause a stack overflow.
This recursive function does basically create a string of the last character and then call itself again with the rest of the string excluding the last character. The real switching happens at the last line where last+reversed is returned. If it would be the other way around nothing would happen.
It is very inefficient but it works to show the concept.
Just to suggest a better way of handling recursion:
String reversal using recursion in C++:
#include <iostream>
#include <string>
using namespace std;
string reverseStringRecursively(string str){
if (str.length() == 1) {
return str;
}else{
return reverseStringRecursively(str.substr(1,str.length())) + str.at(0);
}
}
int main()
{
string str;
cout<<"Enter the string to reverse : ";
cin>>str;
cout<<"The reversed string is : "<<reverseStringRecursively(str);
return 0;
}
I won't write a full-blown algorithm for you, but here's a hint:
How about swapping the two outermost characters, and then apply the same to the characters in the middle?
Oh, and if that book really proposed string reverse(string str) as an appropriate function signature for this, throw it away and buy a good book instead.
Here is my version of a recursive function that reverses the input string:
void reverse(char *s, size_t len)
{
if ( len <= 1 || !s )
{
return;
}
std::swap(s[0], s[len-1]);// swap first and last simbols
s++; // move pointer to the following char
reverse(s, len-2); // shorten len of string
}
Shortest and easiest
class Solution {
public:
string reverseString(string s) {
string str;
if(s != "\0"){
str = reverseString(s.substr(1, s.length()));
str += s.substr(0,1);
}
return str;
}
};
1-line recursive solution:
string RecursiveReverse(string str, string prev = "") {
return (str.length() == 0 ? prev : RecursiveReverse(str.substr(0, str.length()-1), prev += str[str.length()-1]));
}
You call it like this:
cout << RecursiveReverse("String to Reverse");
I know I shouldn't give a solution, but since no one mentioned this easy solution I though I should share it. I think the code literally is the algorithm so there is no need for a pseudo-code.
void c_plusplus_recursive_swap_reverse(std::string::iterator start,
std::string::iterator end)
{
if(start >= end) {
return;
}
std::iter_swap(start, end);
c_plusplus_recursive_swap_reverse(++start, --end);
}
To call it use:
c_plusplus_recursive_swap_reverse(temp.begin(), temp.end());
All existing solutions had way too much code that didn't really do anything, so, here's my take at it:
#include <iostream>
#include <string>
std::string
r(std::string s)
{
if (s.empty())
return s;
return r(s.substr(1)) + s[0];
}
int
main()
{
std::cout << r("testing") << std::endl;
}
P.S. I stumbled upon this question trying to find a C++ way for std::string of what s+1 for a char * in C is; without going the whole route of s.substr(1, s.length()-1), which looks too ugly. Turns out, there's std::string::npos, which means until the end of the string, and it's already the default value for the second argument, so, s.substr(1) is enough (plus, it also looks more efficient and on par with the simple s + 1 in C).
Note, however, that recursion in general doesn't scale as the input grows larger, unless the compiler is able to do what is known as tail-recursion optimisation. (Recursion is rarely relied upon in imperative languages.)
However, in order for the tail recursion optimisation to get activated, it is generally required that, (0), the recursion only happens within the return statement, and that, (1), no further operations are performed with the result of the recursive call back in the parent function.
E.g., in the case above, the + s[0] is logically done by the parent after the child call completes (and it probably would be so even if you go the more uglier s[s.length()-1] + route), so, it might as well prevent most compilers from doing a tail-recursion-optimisation, thus making the function very inefficient on large inputs (if not outright broken due to heap exhaustion).
(For what it's worth, I've tried writing a more tail-recursion-friendly solution (making sure to grow the return result through an argument to the function itself), but disassembly of the resulting binary seems to suggest that it's more involved than that in the imperative languages like C++, see gcc: is there no tail recursion if I return std::string in C++?.)
you can implement your own reverse similar to std::reverse.
template <typename BidirIt>
void reverse(BidirIt first, BidirIt last)
{
if((first == last) || (first == --last))
return;
std::iter_swap(first, last);
reverse(++first, last);
}
I did something like this, it did the reversal in place. I took two variables that traverse the string from two extreme end to the centre of the string and when they overlap or equal to each other then reversal terminates.
Take an example: input string str = "abcd" and call the function as
ReverseString(str,0,str.length()-1);
and increment/decrement the variable pointers recursively.
First the pointers points to 'a' and 'd' and swap them, then they point to 'b' and 'c' and swap them. Eventually i >= j which calls for the base case to be true and hence the recursion terminates. The main take away for this question is to pass input string as reference.
string ReverseString(string& str,int i,int j){
if(str.length() < 1 || str == "" || i >= j){
return "";
}
else{
char temp = str[i];
str[i] = str[j];
str[j] = temp;
ReverseString(str,i+1,j-1);
}
return str;
}
String can be reversed in-place. If we start from smallest possible string i.e. one character string, we don't need to do anything. This is where we stop or return from our recursive call and it becomes our base case.
Next, we have to think of a generic way to swap the smallest string i.e. two characters or more. Simplest logic is to swap the current character str[current_index] with character on the opposite side str[str_length-1 - current_index].
In the end, call the reverse function again for next index.
#include <iostream>
using namespace std;
void reverse_string(std::string& str, int index, int length) {
// Base case: if its a single element, no need to swap
// stop swapping as soon as we reach the mid, hence index*2
// otherwise we will reverse the already reversed string
if( (length - index*2) <= 1 ) {
return;
}
// Reverse logic and recursion:
// swap current and opposite index
std::swap(str[index], str[length-1 - index]);
// do the same for next character (index+1)
reverse_string(str, index+1, length);
}
int main() {
std::string s = "World";
reverse_string(s, 0, s.length());
std::cout << s << endl;
}
There are already some good answer but I want to add my approach with full working Recursive reversing string.
#include <iostream>
#include <string>
using namespace std;
char * reverse_s(char *, char*, int,int);
int main(int argc, char** argv) {
if(argc != 2) {
cout << "\n ERROR! Input String";
cout << "\n\t " << argv[0] << "STRING" << endl;
return 1;
}
char* str = new char[strlen(argv[1])+1];
strcpy(str,argv[1]);
char* rev_str = new char[strlen(str)+1];
cout<<"\n\nFinal Reverse of '" << str << "' is --> "<< reverse_s(str, rev_str, 0, strlen(str)) << endl;
cin.ignore();
delete rev_str, str;
return 0;
}
char* reverse_s(char* str, char* rev_str, int str_index, int rev_index ) {
if(strlen(str) == 1)
return str;
if(str[str_index] == '\0' ) {
rev_str[str_index] = '\0';
return rev_str;
}
str_index += 1;
rev_index -=1;
rev_str = reverse_s(str, rev_str, str_index, rev_index);
if(rev_index >= 0) {
cout << "\n Now the str value is " << str[str_index-1] << " -- Index " << str_in
dex << " Rev Index: " << rev_index;
rev_str[rev_index] = str[str_index-1];
cout << "\nReversed Value: " << rev_str << endl;
}
return rev_str;
}
void reverse(string &s, int &m) {
if (m == s.size()-1)
return;
int going_to = s.size() - 1 - m;
string leader = s.substr(1,going_to);
string rest = s.substr(going_to+1,s.size());
s = leader + s.substr(0,1) + rest;
reverse(s,++m);
}
int main ()
{
string y = "oprah";
int sz = 0;
reverse(y,sz);
cout << y << endl;
return 0;
}
void ClassName::strgRevese(char *str)
{
if (*str=='\0')
return;
else
strgRevese(str+1);
cout <<*str;
}
here is my 3 line string revers
std::string stringRevers(std::string s)
{
if(s.length()<=1)return s;
string word=s.at(s.length()-1)+stringRevers(s.substr(0,s.length()-1));//copy the last one at the beginning and do the same with the rest
return word;
}
The question is to write a recursive function. Here is one approach. Not a neat code, but does what is required.
/* string reversal through recursion */
#include <stdio.h>
#include <string.h>
#define size 1000
char rev(char []);
char new_line[size];
int j = 0;
int i =0;
int main ()
{
char string[]="Game On";
rev(string);
printf("Reversed rev string is %s\n",new_line);
return 0;
}
char rev(char line[])
{
while(line[i]!='\0')
{
i++;
rev(line);
i--;
new_line[j] = line[i];
j++;
return line[i];
}
return line[i];
}
It will reverse Original string recursively
void swap(string &str1, string &str2)
{
string temp = str1;
str1 = str2;
str2 = str1;
}
void ReverseOriginalString(string &str, int p, int sizeOfStr)
{
static int i = 0;
if (p == sizeOfStr)
return;
ReverseOriginalString(str, s + 1, sizeOfStr);
if (i <= p)
swap(&str[i++], &str[p])
}
int main()
{
string st = "Rizwan Haider";
ReverseOriginalString(st, 0, st.length());
std::cout << "Original String is Reversed: " << st << std::endl;
return 0;
}