Can anyone help me in decreasing the complexity of the code below which counts the number of trailing blank spaces in a string.
void main()
{
string url = "abcd ";
int count = 1;
for (int i = 0; i < url.length(); i++)
{
if (url.at(i) == ' ')
{
for (int k = i + 1; k < url.length(); k++)
{
if (url.at(k) != ' ')
{
count = 1;
break;
}
else
{
count++;
i++;
}
}
}
}
cout<< count;
}
#include <iostream>
#include <string>
#include <algorithm>
#include <cstring>
using namespace std;
int main()
{
string url = "abcd "; // four spaces
string rev = url;
reverse(rev.begin(), rev.end());
cout << "There are " << strspn(rev.c_str(), " ") << " trailing spaces." << endl;
return 0;
}
We can do this without reversing the string, and without using a C function like strspn. For example, look up the string::find_last_not_of function. It will find the last character in the string which is not in the specified set, and return its position. If your set is the set " " (space) then it finds the last non-space character. The difference between that position and the string length is the count of trailing spaces.
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
int main()
{
string url = "abcd "; // four spaces
size_t last_nonspace = url.find_last_not_of(" ");
cout << "There are " << url.length() - last_nonspace - 1 << " trailing spaces." << endl;
return 0;
}
Note that if there is no non-space character in the string (the string is either empty or contains only spaces), the find_last_not_of function returns string::npos which is just (size_t) -1, the largest value of size_t. When this is subtracted from the length, and then 1 is subtracted, the resulting value is just the length. The arithmetic works out in all cases.
start backward counting the white space
void main() {
string url = "abcd ";
int count = 0;
for (int i = url.length(); i > 0; i--) {
if (url.at(i) == ' ') {
count++;
} else {
break;
}
}
cout<< count;
}
You can do this by using the find_if() algorithm function:
#include <algorithm>
#include <string>
#include <cctype>
#include <iostream>
using namespace std;
int main()
{
string s = "This string has spaces at the end ";
string::iterator it =
find_if(s.rbegin(), s.rend(), [](char ch) { return !isspace(ch); }).base();
cout << "The number of trailing spaces is " << std::distance(it, s.end());
}
Basically we start from the end of the string, and let find_if() find the first non-space character (I used isspace instead of the hard-coded 32).
After that, the iterator that is returned will point to the non-space character, so it's a matter of just knowing the "distance" between that point and the end (that is what std::distance will do for us).
Related
I wrote this code to detect if an input string has a space or not. Please tell what is wrong in this approach.
#include <iostream>
#include <string>
using namespace std;
int main(){
string inp;
getline(cin, inp);
for (int i = 0; i < inp.length(); i++) {
string z = to_string(inp[i]);
if (z == " ") {
cout << "space";
}
else {
i++;
}
}
}
If i enter a string with spaces, it doesn't print "space".
Since inp is an std::string, inp[i] will be a char. Since std::to_string only has overloads for arithmetic, non-char values, calling it on a char is akin to calling it on the integer representation of said char. (If you log z, you'll likely find a number printed.)
Instead, directly compare inp[i] to a space. else { i++; } is also unnecessary – you may be jumping over spaces.
for (int i = 0; i < inp.length(); i++) {
if (inp[i] == ' ') { // note single quotes for char
cout << "space";
}
}
#TrebledJ's answer explains why your code is broken and how to fix it.
Another way to handle this situation is to use std::string::find() instead:
#include <iostream>
#include <string>
int main(){
std::string inp;
std::getline(std::cin, inp);
if (inp.find(' ') != std::string::npos) {
std::cout << "space";
}
}
Alternatively, your original code tries to output "space" for each space character found. You could use find() in a loop:
#include <iostream>
#include <string>
int main(){
std::string inp;
std::getline(std::cin, inp);
std::string::size_type idx = inp.find(' ');
while (idx != std::string::npos) {
std::cout << "space at " << idx << std::endl;
idx = inp.find(' ', idx+1);
}
}
I am trying to make a program in which a user enters a string and i will print out the second word in the string with its size.
The delimiter's are space( ), comma(,) and tab( ).
I have used a character array and fgets to read from user and a character pointer that points to the first element of the array.
source code:
#include"iostream"
#include<stdio.h>
#include<string>
using namespace std;
// extract the 2nd word from a string and print it with its size(the number of characters in 2nd word)
int main()
{
char arr[30], arr1[30];
char *str = &arr1[0];
cout<<"Enter a string: ";
fgets(str, 30, stdin);
int i = 0, j, count = 1, p = 0; // count is used to find the second word
// j points to the next index where the first delimiter is found.
// p is used to store the second word found in character array 'arr'
while(*(str+i) != '\n')
{
if(*(str+i) == ' ' || *(str+i) == ',' || *(str+i) == ' ')
{
count++;
if(count == 2)
{
// stroing 2nd word in arr character array
j = i+1;
while(*(str+j) != ' ' || *(str+j) != ',' || *(str+j) != ' ')
{
arr[p] = *(str+j);
cout<<arr[p];
p++;
i++;
j++;
}
break;
}
}
i++;
}
arr[p+1] = '\0'; // insert NULL at end
i = 0;
while(arr[i] != '\0')
{
cout<<arr[i];
i++;
}
cout<<"("<<i<<")"<<endl;
return 0;
}
Help me out with this.
To start, don't use std::cin for testing. Just set a value in your code for consistency and ease of development. Use this page for a reference.
#include <iostream>
#include <string>
int main() {
std::string str("this and_that are the tests");
auto start = str.find_first_of(" ,\n", 0);
auto end = str.find_first_of(" ,\n", start + 1);
std::cout << str.substr(start, end - start);
return 0;
}
And this is still somewhat of a hack, it just depends where you are going. For instance the Boost library is rich with extended string manipulation. If you are going to parse out more than just one word it can still be done with string manipulations, but ad-hoc parsers can get out of hand. There are other tools like Boost Spirit to keep code under control.
The delimiters used when extracting from a stream depends on the locale currently in effect. One (cumbersome) way to change the extraction behaviour is to create a new locale with a special facet in which you specify your own delimiters. In the below example the new locale is used to imbue a std::stringstream instead of std::cin directly. The facet creation part is mostly copy/paste from other answers here on SO, so you'll find plenty of other examples.
#include <iostream>
#include <locale> // std::locale, std::ctype<char>
// https://en.cppreference.com/w/cpp/locale/ctype_char
#include <sstream> // std::stringstream
#include <algorithm> // std::copy_n
#include <vector> // a container to store stuff in
// facet to create our own delimiters
class my_facet : public std::ctype<char> {
mask my_table[table_size];
public:
my_facet(size_t refs = 0)
: std::ctype<char>(&my_table[0], false, refs)
{
// copy the "C" locales table to my_table
std::copy_n(classic_table(), table_size, my_table);
// and create our delimiter specification
my_table[' '] = (mask)space;
my_table['\t'] = (mask)space;
my_table[','] = (mask)space;
}
};
int main() {
std::stringstream ss;
// create a locale with our special facet
std::locale loc(std::locale(), new my_facet);
// imbue the new locale on the stringstream
ss.imbue(loc);
while(true) {
std::string line;
std::cout << "Enter sentence: ";
if(std::getline(std::cin, line)) {
ss.clear(); // clear the string stream from prior errors etc.
ss.str(line); // assign the line to the string stream
std::vector<std::string> words; // std::string container to store all words in
std::string word; // for extracting one word
while(ss>>word) { // extract one word at a time using the special facet
std::cout << " \"" << word << "\" is " << word.size() << " chars\n";
// put the word in our container
words.emplace_back(std::move(word));
}
if(words.size()>=2) {
std::cout << "The second word, \"" << words[1] << "\", is " << words[1].size() << " chars\n";
} else {
std::cout << "did not get 2 words or more...\n";
}
} else break;
}
}
#include"iostream"
#include<stdio.h>
#include<string>
#include <ctype.h>
using namespace std;
int main()
{
char c;
string str;
char emp = ' ';
cout<<"Enter a string: ";
getline (cin,str);
int j = 0, count = 1, counter = 0;
for (int i = 0; i < str.length() && count != 2; i++)
{
cout<< str[i] <<endl;
if( isspace(str[i]) || str[i] == ',' || str[i] == '\t' )
{
count++;
if(count == 2)
{
j = i+1;
while(j < str.length())
{
if (isspace(str[j]) || str[j] == ',' || str[j] == '\t')
{
break;
}
cout<<str[j];
counter++;
j++;
}
cout<<endl;
}
}
}
cout<<"size of the word: "<<counter<<endl;
return 0;
}
This is a simple answer to what you want, hope to help you.
// Paul Adrian P. Delos Santos - BS Electronics Engineering
// Exercise on Strings
#include <iostream>
#include <sstream>
using namespace std;
int main(){
// Opening Message
cout << "This program will display the second word and its length.\n\n";
// Ask for a string to the user.
string input;
cout << "Now, please enter a phrase or sentence: ";
getline(cin, input);
// Count the number of words to be used in making a string array.
int count = 0;
int i;
for (i=0; input[i] != '\0'; i++){
if (input[i] == ' ')
count++;
}
int finalCount = count + 1;
// Store each word in a string array.
string arr[finalCount];
int j = 0;
stringstream ssin(input);
while (ssin.good() && j < finalCount){
ssin >> arr[j];
j++;
}
// Display the second word and its length.
string secondWord = arr[1];
cout << "\nResult: " << arr[1] << " (" << secondWord.size() << ")";
return 0;
}
how can I print a single word from a string in each line with the number of characters right next to it and the average of the characters together? I'm suppose to use a string member function to convert the object into a c string. The function countWords accepts the c string and returns an int. The function is suppose to read in each word and their lengths including the average of characters. I have done how much words are in the string except I don't know how continue the rest.
For example: super great cannon boys
super 5
great 5
cannon 6
boys 4
average of characters: 5
This is my program so far:
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
int countWords(char *sentence);
int main()
{
const int size=80;
char word[size];
double average=0;
cout<<"Enter words less than " <<size-1<<" characters."<<endl;
cin.getline(word, size);
cout <<"There are "<<countWords(word)<<" words in the sentence."<<endl;
return 0;
}
int countWords(char *sentence)
{
int words= 1;
while(*sentence != '\0')
{
if(*sentence == ' ')
words++;
sentence++;
}
return words;
}
Unless this is something like homework that prohibits doing so, you almost certainly want to use std::string along with the version of std::getline that works with a std::string instead of a raw buffer of char:
std::string s;
std::getline(std::cin, s);
Then you can count the words by stuffing the line into a std::istringstream, and reading words out of there:
std::istringstream buffer(s);
auto word_count = std::count(std::istream_iterator<std::string>(s),
std::istream_iterator<std::string());
To print out the words and their lengths as you go, you could (for example) use std::for_each instead:
int count = 0;
std::for_each(std::istream_iterator<std::string>(s),
std::istream_iterator<std::string>(),
[&](std::string const &s) {
std::cout << s << " " << s.size();
++count;});
This should not be far from you requirements - I only did minimal modification to your present code.
Limits :
you'd better use
string line;
getline(cin, line);
to read the line to be able to accept lines of any size
my present code assumes
no spaces at beginning or end of line
one single space between 2 words
it should be improved to cope with extra spaces, but I leave that to you as an exercise :-)
The code :
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
int countWords(char *sentence, double& average);
int main()
{
const int size=80;
char word[size];
double average=0;
cout<<"Enter words less than " <<size-1<<" characters."<<endl;
cin.getline(word, size);
cout <<"There are "<<countWords(word, average)<<" words in the sentence."<<endl;
cout << "Average of the sentence " << average << endl;
return 0;
}
int countWords(char *sentence, double& average)
{
int words= 1;
int wordlen;
char *word = NULL;
while(*sentence != '\0')
{
if(*sentence == ' ') {
words++;
wordlen = sentence - word;
average += wordlen;
*sentence = '\0';
cout << word << " " << wordlen<< endl;
word = NULL;
}
else if (word == NULL) word = sentence;
sentence++;
}
wordlen = sentence - word;
average += wordlen;
cout << word << " " << wordlen<< endl;
average /= words;
return words;
}
For input : super great cannon boys
Output is :
Enter words less than 79 characters.
super great cannon boys
super 5
great 5
cannon 6
boys 4
There are 4 words in the sentence.
Average of the sentence 5
You can inspire here. Basically use std::getline to read from std::cin to std::string.
#include <iostream>
#include <string>
#include <cctype>
inline void printWordInfo(std::string& word) {
std::cout << "WORD: " << word << ", CHARS: " << word.length() << std::endl;
}
void printInfo(std::string& line) {
bool space = false;
int words = 0;
int chars = 0;
std::string current_word;
for(std::string::iterator it = line.begin(); it != line.end(); ++it) {
char c = *it;
if (isspace(c)) {
if (!space) {
printWordInfo(current_word);
current_word.clear();
space = true;
words++;
}
}
else {
space = false;
chars++;
current_word.push_back(c);
}
}
if (current_word.length()) {
words++;
printWordInfo(current_word);
}
if (words) {
std::cout << "AVERAGE:" << (double)chars/words << std::endl;
}
}
int main(int argc, char * argv[]) {
std::string line;
std::getline(std::cin, line);
printInfo(line);
return 0;
}
Going along the lines of what you already have:
You could define a countCharacters function, like your countWords:
int countCharacters(char *sentence)
{
int i;
char word[size];
for(i = 0; sentence[i] != ' '; i++) //iterate via index
{
word[i] = sentence[i]; //save the current word
i++;
}
cout <<word<< <<i<<endl; //print word & number of chars
return i;
}
which you can call inside your countWords function
int countWords(char *sentence)
{
int words = 1;
for(int i; sentence[i] != '\0';) //again this for loop, but without
//increasing i automatically
{
if(sentence[i] == ' ') {
i += countCharacters(sentence[++i]); //move i one forward to skip
// the space, and then move
// i with the amount of
// characters we just counted
words++;
}
else i++;
}
return words;
}
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;
}
I'm trying to read a string that will show digits and characters separately.
Additional Info:
1. the program is showing 10 (ten) as 1 and 0 i.e two separate digits
2. It is also counting space as a character, which it should skip.
3. If a user input 10 20 + it should display:
digit is 10
digit is 20
other Character is +
Here is what I've tried
#include <iostream>
#include <string>
using namespace std;
int main() {
string s("10 20 +");
const char *p = s.c_str();
while (*p != '\0')
{
if(isdigit(*p))
{
cout << "digit is: "<< *p++ << endl;
}
else
{
cout<<"other charcters are:"<<*p++<<endl;
}
}
system("pause");
}
Edit Now it becomes :
#include <iostream>
#include <string>
using namespace std;
int main() {
string x;
string s("1 2 +");
const char *p = s.c_str();
while (*p != '\0')
{
while(isspace(*p)){
*p++;
if(isdigit(*p))
{
while(isdigit(*p))
{
x+=*p++;
cout << "digit is: "<< x<< endl;
}
}
else{
while(!isdigit(*p)&& !isspace(*p))
x+=*p++;
cout<<"other charcters are:"<<x<<endl;
}
}
}
system("pause");
}
Not workingg
You could use a stringstream instead.
[...]
stringstream ss;
ss << s;
while(!ss.eof())
{
char c = ss.peek(); // Looks at the next character without reading it
if (isdigit(c))
{
int number;
ss >> number;
cout << "Digit is: " << number;
}
[...]
}
While the character is space (check the isspace function) skip it.
If the current character is a digit, then while the current character is a digit put it in a temporary string. When the character is no longer a digit, you have a number (which might be a single digit).
Else if the character is not a digit or not a space, do the same as for numbers: collect into a temporary string and display when it ends.
Start over.
Edit Code sample on request:
std::string expression = "10 20 +";
for (std::string::const_iterator c = expression.begin(); c != expression.end(); )
{
std::string token;
// Skip whitespace
while (isspace(*c))
c++;
if (isdigit(*c))
{
while (isdigit(*c))
token += *c++;
std::cout << "Number: " << token << "\n";
}
else
{
while (!isidigit(*c) && !isspace(*c))
token += *c++;
std::cout << "Other: " << token << "\n";
}
}