How to iterate over the words of a sentence in C++? - c++

My input is "Hello World" and my targeted output is "olleH dlroW".
So my idea is to get the sentence into a variable and then loop over the words in the sentence, reverse each of them and finally concatenate them into a new variable.
My question is: how to iterate over the words of the sentence?
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
string reverseword(string word)
{
string rword;
int size = word.length();
while (size >= 0)
{
rword+= word[size];
size = size -1;
}
return rword;
}
int main()
{
string sentence;
cout<<"Enter the word/sentence to be reversed: ";
cin >> sentence;
string rsentence;
// for every word in the sentence do
{
rword = reverseword(word);
rsentence = rsentence + " " + rword;
}
cout<<rword;
return 0;
}

Before you can iterate over words in a sentence, you need to read a sentence from input. This line
cin >> sentence;
reads the first word of a sentence, not the whole sentence. Use getline instead:
std::getline(std::cin, sentence);
With sentence in memory, you can iterate it word-by-word using istream_iterator as follows:
stringstream ss(sentence);
for (auto w = istream_iterator<string>(ss) ; w != istream_iterator<string>() ; w++) {
string &word = *w;
...
}
Demo.

Here is a solution that uses find and reverse to achieve the output:
#include <iostream>
#include <string>
#include <algorithm>
int main() {
std::string sentence;
std::getline(std::cin, sentence);
std::cout << sentence << std::endl;
size_t cpos = 0;
size_t npos = 0;
while((npos = sentence.find(' ', cpos)) != std::string::npos)
{
std::reverse(sentence.begin() + cpos, sentence.begin() + npos);
cpos = npos + 1;
}
std::reverse(sentence.begin() + cpos, sentence.end());
std::cout << sentence << std::endl;
return 0;
}
Input:
this is a nice day
Output:
this is a nice day
siht si a ecin yad

for(short i=0;i<sentence.length();i++){
if(sentence[i] == ' '){
counter++;
i++;
}
words[counter] += sentence[i];
}
Note the above loop to split the sentence with space and store it to a string array, words[]
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
string reverseword(string word) // function to reverse a word
{
string rword;
int size = word.length();
while (size >= 0)
{
rword+= word[size];
size = size -1;
}
return rword;
}
int main()
{
string sentence;
cout << "Enter the word/sentence to be reversed: ";
std::getline(std::cin, sentence);
string rsentence;
string words[100];
string rword;
short counter = 0;
for(short i=0; i<sentence.length(); i++){ // looping till ' ' and adding each word to string array words
if(sentence[i] == ' '){
counter++;
i++;
}
words[counter] += sentence[i];
}
for(int i = 0; i <= counter; i++) // calling reverse function for each words
{
rword = reverseword(words[i]);
rsentence = rsentence + " " + rword; // concatenating reversed words
}
cout << rsentence; // show reversed word
return 0;
}
I have corrected the code. Hope this helps...!!
NB : You were using cin to read space seperated string that is not possible. You must use std::getline(std::cin, sentence) to read space separated strings.
You can also use std::reverse() to reverse a string

Please refer to Most elegant way to split a string?
to split your sentence into tokens(words)
then, iterate over the new list of words to perform any operation

An answers above gives a way to convert your input to words, i.e., cin >> sentence returns a "word" (so, just call it repeatedly).
However, this brings up the question of what is a "word". You would like to translate a computer construct - string of characters - into a more complex form - words. So, you must define what you mean when you want words. It can be as simple as "space" separated substrings or your string - then use the split function, or read your string a word at a time (cin >> word)
Or you may have more stringent requirements, like they can't include punctuation (like a period at the end of a sentence) or numbers. Then think about using Regex and word patterns (like, "\w+").
Or you may want "real" words like you would find in a dictionary. Then you need to take into account your locale, parse your input into chunks (using split, Regex, or something), and look up each chunk in a human language dictionary.
In other words, "word" parsing is only as simple or complex as your requirements are.

With Boost you could use the boost::split function:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <boost/algorithm/string.hpp>
int main()
{
std::string sentence = "Hello world";
std::vector<std::string> words;
boost::split(words, sentence, boost::is_any_of(" "));
std::string rsentence;
for (std::string word : words) // Iterate by value to keep the original data.
{
std::reverse(word.begin(), word.end());
rsentence += word + " "; // Add the separator again.
}
boost::trim(rsentence); // Remove the last space.
std::cout << rsentence << std::endl;
return 0;
}

This answer is my humble contribution to the fight against global warming.
#include <string>
#include <iostream>
#include <algorithm>
#include <cctype>
int main()
{
std::string sentence;
while (std::getline(std::cin, sentence))
{
auto ws = sentence.begin();
while (ws != sentence.end())
{
while (std::isspace(*ws)) ++ws;
auto we = ws;
while (we != sentence.end() && !std::isspace(*we)) ++we;
std::reverse(ws, we);
ws = we;
}
std::cout << sentence << "\n";
}
}
This assumes "word" is defined as "a sequence of non-whitespace characters". It is easy to substitute a different character class instead of "non-whitespace", e.g. for alphanumeric characters use std::isalnum. A definition that reflects the real-world notion of word as e.g. used in natural language sciences is far far beyond the scope of this answer.

Related

Finding and changing repeated letters in a word

I'm trying to create logic that goes through the word and tries to find if there are letters, that are used more than once. If a letter repeats, then change it to "1", if it's not then change it to "2". Example: Radar - 11211, Amazon - 121222, karate - 212122.
Specific problem is that if I use for(), each letter compares to the last one. Also I don't understand how can I check last letter by using for().
Last letter is always 2.
Here is my code:
#include <iostream>
#include <string>
using namespace std;
int main()
{ string word;
char bracket1('1');
char bracket2('2');
cout << "Write your word: ";
cin >> word;
for (int i = 0; i < word.length(); ++i)
{
char let1 = word[i];
char let2 = word[i+1];
if (let1 == let2)
{ word[i] = bracket1;}
else
{ word[i] = bracket2; }
} cout << word;
}
Example: test returns 1e22 instead of 1221
You have undefined behavior in your program when wrote word[i+1]; inside the for loop. This is because you're going out of bounds for the last value of i by using i+1.
One possible way to solve this would be to use std::map as shown below. In the program given std::tolower is used because you want capital and small letters to be treated the same.
#include <iostream>
#include <map>
#include <algorithm>
int main()
{
std::string word;
std::cout << "Write your word: ";
std::getline(std::cin, word);
//print out the word before replacing with 1 and 2
std::cout<<"Before transformation: "<<word<<std::endl;
std::map<char, int> charCount; //this map will keep count of the repeating characters
//iterate through each character in the input word and populate the map
for(char &c: word)
{
charCount[std::tolower(c)]++;//increment the value by 1
}
//replace the repeating characters by 1 and non-repeating by 2
for(char &c: word)
{
if(charCount.at(std::tolower(c)) > 1)
{
c = '1';
}
else
{
c = '2';
}
}
//print out the word after transformation
std::cout<<"After transformation: "<<word<<std::endl;
return 0;
}
The output of the program can be seen here.
Output for the input Amazon is:
Write your word: Amazon
Before transformation: Amazon
After transformation: 121222

How to convert a sentence from upper case to lower case that contains space and numbers

I'm trying to convert a sentence from upper case to lowercase. I also write a code but I stopper when a space is appear. How can I fix this problem and convert the whole sentence? Here is my code
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char str[100];
cin>>str;
for(int i=0;i<strlen(str);i++)
{
if(str[i]>='A'&&str[i]<='Z')
{
str[i]=str[i]+32;
}
}
cout<<str<<endl;
return 0;
}
It's because of theinput operator >>, it breaks on space. If you want to read a whole line then use std::getline to read into a std::string instead.
Then read about the C++ standard algorithms, like for example std::transform. Also, std::tolower doesn't modify anything that's not an upper-case letter, so it's a good function to use.
The error is because operator>> delimites on spaces. The alternative is to use getline. See the following example:
#include <cstring>
#include <iostream>
#include <string>
int main() {
std::string s;
std::getline(std::cin, s);
std::cout << "Original string: " << s << std::endl;
if (!std::cin.fail()) {
const int len = strlen(s.c_str());
for (size_t i = 0; len > i; ++i) {
if ((s[i] >= 'A') && (s[i] <= 'Z'))
s[i] = s[i] - 'A' + 'a';
}
}
std::cout << "New string: " << s << std::endl;
return 0;
}
The reason input stops at whitespace is because formatted input is delimited by whitespace characters (among others). You will need unformatted I/O in order to extract the entire string into str. One way to do this is to use std::istream::getline:
std::cin.getline(str, 100, '\n');
It's also useful to check if the input succeeded by using gcount:
if (std::cin.getline(str, 100, '\n') && std::cin.gcount())
{
...
}
But in practice it's recommended that you use the standard string object std::string which holds a dynamic buffer. To extract the entire input you use std::getline:
std::string str;
if (std::getline(std::cin, str)
{
...
}
Here is one of the examples of doing it using transform function.
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string str;
if (getline(cin, str))
{
transform(str.begin(), str.end(), str.begin(), ptr_fun<int, int>(toupper));
}
cout << str << endl;
return 0;
}

Locate and tag words in text file

I need to read in a text file of 500 words or more(a real world article from newspaper, etc..) and locate and tag like this, <location> word <location/>, and then print the entire article on the screen. Im using boost regex right now and its working ok. I want to try and use a list or array or some other data structure to have a list of the states and major cities, and search those and compare to the aticle. right now I'm using an array but I'm willing to use anything. Any ideas or clues?
#include <boost/regex.hpp>
#include <iostream>
#include <string>
#include <boost/iostreams/filter/regex.hpp>
#include <fstream>
using namespace std;
int main()
{
string cities[389];
string states [60];
string filename, line,city,state;
ifstream file,cityfile, statefile;
int i=0;
int j=0;
cityfile.open("c:\\cities.txt");
while (!cityfile.eof())
{
getline(cityfile,city);
cities[i]=city;
i++;
//for (int i=0;i<500;i++)
//file>>cities[i];
}
cityfile.close();
statefile.open("c:\\states.txt");
while (!statefile.eof())
{
getline(statefile,state);
states[j]=state;
//for (int i=0;i<500;i++)
//cout<<states[j];
j++;
}
statefile.close();
//4cout<<cities[4];
cout<<"Please enter the path and file name "<<endl;
cin>>filename;
file.open(filename);
while (!file.eof())
{
while(getline(file, line)
{
}
while(getline(file, line))
{
//string text = "Hello world";
boost::regex re("[A-Z/]\.[A-Z\]\.|[A-Z/].*[:space:][A-Z/]|C........a");
//boost::regex re(
string fmt = "<locations>$&<locations\>";
if(boost::regex_search(line, re))
{
string result = boost::regex_replace(line, re, fmt);
cout << result << endl;
}
/*else
{
cout << "Found Nothing" << endl;
}*/
}
}
file.close();
cin.get(),cin.get();
return 0;
}
If you are after asymptotic complexity - Aho-Corasick algorithm offers a linear time complexity ( O(n+m)) (n and m are the lengths of the input strings). for searching a dictionary in a string.
An alternative is to put the tokenized words in a map (where the value is a list to the places in the stream of each string), and search for each string in the data in the tree. The complexity will be O(|S| * (nlogn + mlogn) ) (m being the number of searched words, n is the number of words in the string, and |S| is the length of the average word)
You can use any container that has a .find() method or supports std::find(). I'd use set, since set::find() runs in less than linear time.
Here is a program which does what you talk about. Note that the parsing doesn't work great, but that's not what I'm trying to demonstrate. You could continue to find the words using your parser, and use the call to set::find() to determine if they are locations.
#include <set>
#include <string>
#include <iostream>
#include <sstream>
const std::set<std::string> locations { "Springfield", "Illinois", "Pennsylvania" };
int main () {
std::string line;
while(std::getline(std::cin, line)) {
std::istringstream iss(line);
std::string word;
while(iss >> word) {
if(locations.find(word) == locations.end())
std::cout << word << " ";
else
std::cout << "<location>" << word << "</location> ";
}
std::cout << "\n";
}
}

Double space after period remover

People who learned how to type before word processors often add two spaces after a period ending a sentence. Write a function singleSpaces that accepts a string and returns that string with all occurrences of two spaces after a "." into changed single spaces.)
This is what I have; what am I doing wrong?
#include <cmath>
#include <iostream>
using namespace std;
string forceSingleSpaces1 (string s) {
string r = "";
int i = 0;
while (i < static_cast <int> (s.length())) {
if (s.at(i) != ' ') {
r = r + s.at(i);
i++;
} else {
r += ' ';
while (i < static_cast <int> (s.length()) && s.at(i) == ' ')
i++;
}
}
return r;
}
In your assignment there is talk about double spaces after dot, and not all double spaces in text. So you should modify your code so that it
waits for a '.'and not ' ',
when '.' is intercepted then add it, after that add any single space
you can think of this code as two states machine:
state 1 - is when you are looping on any non '.' character, in this state your code adds to result all what it finds
state 2 - is when '.' is found, and in this state you use different code, you add '.' to results and ater that exactly single space (if any one was found)
this way you have your problem divided into two sub problems
[edit] - replaced source code with modification hints
You might (re)use a more general function that replaces occurrences of a given string within a string with another string, as described here.
#include <string>
#include <iostream>
void replace_all(std::string& str, const std::string& from, const std::string& to) {
size_t start_pos = 0;
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
}
}
int main() {
std::string text = "I'm old. And I use two spaces. After periods.";
std::string newstyle_text(text);
replace_all(newstyle_text, ". ", ". ");
std::cout << newstyle_text << "\n";
return 0;
}
Update
If you are not afraid of being on the cutting edge, you might consider using TR1 regular expressions. Something like this should work:
#include <string>
#include <regex>
#include <iostream>
int main() {
std::string text = "I'm old. And I use two spaces. After periods.";
std::regex regex = ". ";
std::string replacement = ". ";
std::string newstyle_text = std::regex_replace(text, regex, repacement);
std::cout << newstyle_text << "\n";
return 0;
}
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
//1. loop through the string looking for ". "
//2. when ". " is found, delete one of the spaces
//3. Repeat process until ". " is not found.
string forceSingleSpaces1 (string str) {
size_t found(str.find(". "));
while (found !=string::npos){
str.erase(found+1,1);
found = str.find(". ");
}
return str;
}
int main(){
cout << forceSingleSpaces1("sentence1. sentence2. end. ") << endl;
return EXIT_SUCCESS;
}

Why is this code not reversing the words in a sentence?

So I want to take the words in a sentence and flip the word, and only the word around. For example:
Hello there
would be changed to:
olleH ereht
So I tried doing so with the following code:
#include <iostream> //Include the necessary header files.
#include <string>
#include <vector>
int main (int argc, const char * argv[]) {
std::string sentence("Hello this is a sentence"); //This is the sentence I want to convert.
char *tokens = strtok(strdup(sentence.c_str()), " "); //Tokenize the sentence.
std::string tempToken; //Will use this to store the tokens in reverse.
std::vector< std::string > strings; //This will keep all contents of the converted sentence.
for (int i = (int)sentence.length()-1; i >= 0; i--) { //Go through the sentence backwards.
if (tokens[i] == NULL) { //If tokens[i] == NULL then that was a complete token.
strings.push_back(tempToken); //Push back the reversed token.
tempToken.clear(); //Clear the reversed token so it can be used again to store another reveresed token.
}
else { //Still in the middle of a token
tempToken.append(&tokens[i]); //Since I am iterating backwards this should store the token backwards...
}
}
for (std::vector<std::string>::reverse_iterator it = strings.rbegin(); it != strings.rend(); ++it) { //Because I used strings.push_back(tempToken) I need to go through the vector backwards to maintain the word placement.
std::cout << *it; //Print the words backwards.
}
}
Basically, I take a sentence. Then I tokenize it. Loop through the string backwards and store the characters in a string until I reach the end of the token. When I reach the end of the token, I take the characters I just stored from looping backwards and put it into a vector. Then after I have done this with all the tokens I print out the contents of the vector.
When I run this program the sentence:
Hello this is a sentence
Gets converted to:
ecenceencetencentenceentencesentence sentencea sentence a sentences a sentenceis a sentence is a sentences is a sentenceis is a sentencehis is a sentencethis is a sentence
What am I doing wrong?
Best to forget everything, and write C++ instead:
#include <string>
#include <sstream>
#include <iostream>
void reverse_words(std::string const & sentence)
{
std::istringstream iss(sentence);
std::string word;
while (iss >> word)
{
std::cout << std::string(word.rbegin(), word.rend()) << " ";
}
std::cout << std::endl;
}
The strtok function doesn't tokenize in one call. It returns the next token each time you call it. Read the documentation more closely.
void main(string s){
List<string> strings = new List<string>();
strings = s.split(" ").toList();
string backwards = "";
foreach(string str in strings){
string stri = str;
for(int i = 0; i< str.length(); i++){
backwards += stri.substr(stri.length() - 1);
stri = stri.substr(0,stri.length() -1);
}
backwards += " ";
}
cout << backwards;
}
This is a well know question with a simple trick (to do it in place):
Reverse the string
For each word
Reverse the word
Try:
#include <iostream>
#include <string>
int main()
{
// Get the line
std::string line;
std::getline(std::cin, line);
// Reverse the whole line.
std::reverse(line.begin(), line.end());
// Find the start of the first word
std::string::size_type beg = line.find_first_not_of(" \t");
while(beg != std::string::npos)
{
// Find the end of the word we have found
std::string::size_type end = line.find_first_of(" \t",beg);
end = (end == std::string::npos ? line.size() : end);
// Reverse the word
std::reverse(&line[beg],&line[end]);
// See if we can find the next word
beg = line.find_first_not_of(" \t", end);
}
// Print the result.
std::cout << line << "\n";
}
try this:
string reverseString(string inputStr){
inputStr += ' ';
int len = inputStr.size();
len--;
int j;
for(int i=0;i<=len;i++){
for( j=i ;inputStr[i] != ' ';i++);
int ii=i;
while(j<=ii){
char temp = inputStr[ii];
inputStr[ii] = inputStr[j];
inputStr[j] = temp;
j++;
ii--;
}
}
return inputStr;
}