How to capitalize the first letter of each name in an array? - c++

Here is the question:
Create a function that takes an array of names and returns an array where only the first letter of each name is capitalized.
example
capMe(["mavis", "senaida", "letty"]) âžž ["Mavis", "Senaida", "Letty"]
And the code I wrote to answer this question:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void capme(vector<string> name)
{
char ch;
for(int i = 0; i < name[i].size(); i++)
{
putchar(toupper(name[i][0]));
cout << name[i] << endl;
}
}
int main()
{
vector <string> name = {"mavis", "senaida", "letty"};
capme(name);
return 0;
}
As you can see, it prints "Mmavis", "Ssenaida", "Lletty", which is wrong. Can you guys help me in answering this question as I don't know how?

To change the input argument, we have two choice: make the argument mutable reference, or add a return type, here I choose the first one.
putchar can be used to print only one character, it recommended to use cout to print a string, possible solutions:
with traditional loop: capme
with range for-loop since c++11 : capme2
with stl algorithm transform: capme3
Don't forget to check if the string element is empty, or you may crash while accessing the first character.
To obey the single-responsibility principle (SRP), it's better to print the string vector out of the capme function.
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void capme(vector<string>& name) {
for (int i = 0; i < name[i].size(); i++) {
if (name[i].empty()) continue;
name[i][0] = toupper(name[i][0]);
}
}
void capme2(vector<string>& names) {
for (auto& name : names) {
if (name.empty()) continue;
name[0] = toupper(name[0]);
}
}
void capme3(vector<string>& names) {
std::transform(names.begin(), names.end(), names.begin(), [](auto& s) {
return s.empty() ? s : (s[0] = toupper(s[0]), s);
});
}
Online demo

You have used the wrong function. What you need is a replacement and not a prepend. Try using std::string::operator[] to access the first element of the words in the vector. This is how I would write this code:
std::vector<string> capitaliseInitLetter(std::vector<string> vec) {
for (auto& word : vec) {
word[0] -= 32; //add a check to see if the letter is already capital
}
return vec;
}
The above code is just an example which assumes that the input is valid. You'll have to add checks and exception handling for invalid inputs on your own. (Hint: Take a look at #prehistoricpenguin's answer)

You are calling putchar() which writes a character to standard output, and in this case is printing the first letter of each string in name as uppercase, then you are writing the entire string to standard output immediately after.
Additionally, your function does not meet the requirements you stated above saying it should return an array where the strings have the first letter capitalized.
What you could do is change the signature of capme() to return a std::vector<std::string>, and perhaps utilize the for_each() function to handle changing the first letter of each string in your vector then return it.
For reference:
#include <vector>
#include <string>
#include <algorithm>
#include <cctype>
std::vector<std::string> capme(std::vector<std::string> name)
{
std::for_each(name.begin(), name.end(), [](std::string &s) {
s[0] = toupper(s[0]);
});
return name;
}
Or as kesarling suggested, a simple for each loop:
std::vector<std::string> capme(std::vector<std::string> name)
{
for (auto& s : name) {
s[0] = toupper(s[0]);
}
return name;
}

Related

I used the std::string::substr method inside the if block but if block isn't working

There's a string with the word "WUB" in it, and I need to eliminate this word from the string.
So I used the substring method inside the if block so that while traversing the loop, if block can catch the WUB and instead print 1
#include <bits/stdc++.h>
using namespace std;
int main()
{
string s="WUBhello";
for(int i=0;i<s.length();i++){
if(s.substr(i,i+2)=="WUB"){
cout<<"1 ";
i+=2;
}
else{
cout<<s[i];
}
}
return 0;
}
I'm expecting it will print only "hello" , but it's printing "WUBhello"
You can use std::stringstream too.
Note: Do check the function signature of any standard library function before using it. std::substr's second argument is length of substring.
#include <string>
#include <sstream>
#include <iostream>
std::string remove_substring(const std::string& s, const std::string& key)
{
std::stringstream ss;
for (int i = 0; i < s.length(); )
{
if (s.substr(i, key.length()) == key)
{
i += key.length();
}
else
{
ss << s[i];
i++;
}
}
return ss.str();
}
int main()
{
const std::string s = "WUBhello";
const std::string key = "WUB";
std::cout << remove_substring(s, key);
}
1. The issues in your code:
There are several issues, some bugs and some bad practices (see side notes below).
To begin with, std::string::substr 's second parameter is count - i.e. the number of characters. So in your case it should simply be 3. You also don't check that i < s.length()-3 before using substr.
Then the whole logic of your loop is flawed. Using a debuggers will help you to get more insight. See: What is a debugger and how can it help me diagnose problems?.
2. A better approach:
If you want to remove a substring from a string, you can do the following:
Use std::string::find to find the substring.
Then use std::string::erase to remove it.
Code example:
#include <iostream>
#include <string>
int main()
{
std::string str = "WUBhello";
std::string toRemove = "WUB";
// Find the substring:
auto pos = str.find(toRemove);
if (pos != std::string::npos)
{
// Remove it:
str.erase(pos, toRemove.length());
}
std::cout << str << std::endl;
return 0;
}
Output:
hello
If you want to remove multiple occurances of the substring, you can apply similar logic in a loop:
// Find the 1st occurance substring:
auto pos = str.find(toRemove);
while (pos != std::string::npos)
{
// Remove it:
str.erase(pos, toRemove.length());
// Find the next one:
pos = str.find(toRemove);
}
Some side notes:
Why should I not #include <bits/stdc++.h>?
Why is "using namespace std;" considered bad practice?
The second argument of std::string::substr is exclusive, so it should be i+3. Also, even when the logic is correct, it will print "1 hello".

How do I print the frequency of each word in the given input string using two vectors?

Here is my approach where I have tried to split the string into words and then move forward but this is not working.
For instance, the input is: hey hi Mark hi mark
Then the output should be:
hey-1
hi-2
Mark-1
hi-2
mark-1
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
vector<vector<string> > strs;
string str;
cout<<"Enter your strings"<<endl;
getline(cin, str);
int len=str.length();
int j=0;
string s="";
for(int i=0; i<len; i++){
s+=str[i];
if(str[i+1]==' ' || i+1==len){
strs[0][j]=s;
s="";
j++;
i++;
}
}
strs[0][j]="NULL";
int freq;
vector<int> frequency;
for(int n=0; strs[0][n]!="NULL" ;n++){
freq=1;
for(int m=0; strs[0][m]!="NULL"; m++){
if(strs[0][n]==strs[0][m]){
freq++;
}
frequency.push_back(freq);
}
}
for(int x=0; strs[0][x]!="NULL"; x++){
cout<<strs[0][x]<<" - "<<frequency[x]<<endl;
}
return 0;
}
In your code, you have tried to access string elements via its index, which sometimes raises segmentation fault. To solve your problem, I came up with below mention solution.
#include <iostream>
#include <string>
#include <map>
/* getWordFrequency : function with return type std::map<std::string, int>
Param1: Input string
Param2: Default delimiter as " "(void space).
*/
std::map<std::string, int> getWordFrequency(const char *input_string, char c = ' ')
{
// Container to store output result
std::map<std::string, int> result;
// Iteration loop
do{
// Iteration pointer to iterate Character by Character
const char *begin = input_string;
// Continue loop until delimeter or pointer to self detects
while(*input_string != c && *input_string){
// Jump to next character
input_string++;
}
// Iterator for output result container
std::map<std::string, int>::iterator finder = result.find(std::string(begin, input_string));
// Find element using iterator
if(finder != result.end()){
// Element already present in resultunt map then increment frequency by one
finder->second += 1;
} else {
// If no element found then insert new word with frequency 1
result.insert(std::pair<std::string, int>(std::string(begin, input_string),1));
}
} while (0 != *input_string++); // Continue till end of string
return result;
}
int main()
{
// Your string
std::string input_string = "hey hi Mark hi mark";
// Container to catch result
std::map<std::string, int> frequency = getWordFrequency(input_string.c_str());
// Printing frequency of each word present in string
for (auto element : frequency){
std::cout << element.first << "-" << element.second << std::endl;
}
return 0;
}
So, I think your approach using 2 std::vectors is unfortunately wrong. You do not fully understand the difference between char and std::string.
You need to learn abaout that.
There is a more or less standard approach for counting something in a container, like a string or in general.
We can use an associative container like a std::map or a std::unordered_map. And here we associate a "key", in this case the "word" to count, with a value, in this case the count of the specific word.
And luckily the maps have a very nice index operator[]. This will look for the given key and, if found, return a reference to the value. If not found, then it will create a new entry with the key and return a reference to the new entry. So, in both cases, we will get a reference to the value used for counting. And then we can simply write:
std::map<std::string, int> counter{};
counter[word]++;
And that's it. More is not necessary. Please see:
#include <iostream>
#include <string>
#include <sstream>
#include <unordered_map>
int main() {
// Our test String
std::string text{"hey hi Mark hi mark"};
// Here, we will store the result of the counting
std::unordered_map<std::string, unsigned int> counter;
// Now count all words. This one line does all the counting
for (std::istringstream iss{text}; iss >> text; counter[text]++);
// Show result to user
for (const auto& [word, count] : counter) std::cout << word << '-' << count << ' ';
}
It seems also that splitting a string is some how difficult for you. Also here are many many ppossible solutions available.
One of the more sophisticated and more advanced solution is to use the std::sregex_token_iterator. With that you can easily iterate over patterns (described by a std::regex) in a string.
The final code will look nearly the same, but the result will be better, since for example punctuation can be excluded.
Example:
#include <iostream>
#include <string>
#include <unordered_map>
#include <regex>
#include <iterator>
using Iter = std::sregex_token_iterator;
const std::regex re{R"(\w+)"};
int main() {
// Our test String
std::string text{"hey hi Mark, hi mark."};
// Here, we will store the result of the counting
std::unordered_map<std::string, unsigned int> counter;
// Now count all words. This one line does all the counting
for (Iter word(text.begin(), text.end(), re); word != Iter(); counter[*word++]++);
// Show result to user
for (const auto& [word, count] : counter) std::cout << word << '-' << count << ' ';
}

How to get a word vector from a string?

I want to store words separated by spaces into single string elements in a vector.
The input is a string that may end or may not end in a symbol( comma, period, etc.)
All symbols will be separated by spaces too.
I created this function but it doesn't return me a vector of words.
vector<string> single_words(string sentence)
{
vector<string> word_vector;
string result_word;
for (size_t character = 0; character < sentence.size(); ++character)
{
if (sentence[character] == ' ' && result_word.size() != 0)
{
word_vector.push_back(result_word);
result_word = "";
}
else
result_word += character;
}
return word_vector;
}
What did I do wrong?
Your problem has already been resolved by answers and comments.
I would like to give you the additional information that such functionality is already existing in C++.
You could take advantage of the fact that the extractor operator extracts space separated tokens from a stream. Because a std::string is not a stream, we can put the string first into an std::istringstream and then extract from this stream vie the std:::istream_iterator.
We could life make even more easier.
Since roundabout 10 years we have a dedicated, special C++ functionality for splitting strings into tokens, explicitely designed for this purpose. The std::sregex_token_iterator. And because we have such a dedicated function, we should simply use it.
The idea behind it is the iterator concept. In C++ we have many containers and always iterators, to iterate over the similar elements in these containers. And a string, with similar elements (tokens), separated by a delimiter, can also be seen as such a container. And with the std::sregex:token_iterator, we can iterate over the elements/tokens/substrings of the string, splitting it up effectively.
This iterator is very powerfull and you can do really much much more fancy stuff with it. But that is too much for here. Important is that splitting up a string into tokens is a one-liner. For example a variable definition using a range constructor for iterating over the tokens.
See some examples below:
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
#include <regex>
const std::regex delimiter{ " " };
const std::regex reWord{ "(\\w+)" };
int main() {
// Some debug print function
auto print = [](const std::vector<std::string>& sv) -> void {
std::copy(sv.begin(), sv.end(), std::ostream_iterator<std::string>(std::cout, "\n")); std::cout << "\n"; };
// The test string
std::string test{ "word1 word2 word3 word4." };
//-----------------------------------------------------------------------------------------
// Solution 1: use istringstream and then extract from there
std::istringstream iss1(test);
// Define a vector (CTAD), use its range constructor and, the std::istream_iterator as iterator
std::vector words1(std::istream_iterator<std::string>(iss1), {});
print(words1); // Show debug output
//-----------------------------------------------------------------------------------------
// Solution 2: directly use dedicated function sregex_token iterator
std::vector<std::string> words2(std::sregex_token_iterator(test.begin(), test.end(), delimiter, -1), {});
print(words2); // Show debug output
//-----------------------------------------------------------------------------------------
// Solution 3: directly use dedicated function sregex_token iterator and look for words only
std::vector<std::string> words3(std::sregex_token_iterator(test.begin(), test.end(), reWord, 1), {});
print(words3); // Show debug output
//-----------------------------------------------------------------------------------------
// Solution 4: Use such iterator in an algorithm, to copy data to a vector
std::vector<std::string> words4{};
std::copy(std::sregex_token_iterator(test.begin(), test.end(), reWord, 1), {}, std::back_inserter(words4));
print(words4); // Show debug output
//-----------------------------------------------------------------------------------------
// Solution 5: Use such iterator in an algorithm for direct output
std::copy(std::sregex_token_iterator(test.begin(), test.end(), reWord, 1), {}, std::ostream_iterator<std::string>(std::cout,"\n"));
return 0;
}
You added the index instead of the character:
vector<string> single_words(string sentence)
{
vector<string> word_vector;
string result_word;
for (size_t i = 0; i < sentence.size(); ++i)
{
char character = sentence[i];
if (character == ' ' && result_word.size() != 0)
{
word_vector.push_back(result_word);
result_word = "";
}
else
result_word += character;
}
return word_vector;
}
Since your mistake was only due to the reason, that you named your iterator variable character even though it is actually not a character, but rather an iterator or index, I would like to suggest to use a ranged-base loop here, since it avoids this kind of confusion. The clean solution is obviously to do what #ArminMontigny said, but I assume you are prohibited to use stringstreams. The code would look like this:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string> single_words(string sentence)
{
vector<string> word_vector;
string result_word;
for (char& character: sentence) // Now `character` is actually a character.
{
if (character==' ' && result_word.size() != 0)
{
word_vector.push_back(result_word);
result_word = "";
}
else
result_word += character;
}
word_vector.push_back(result_word); // In your solution, you forgot to push the last word into the vector.
return word_vector;
}
int main() {
string sentence="Maybe try range based loops";
vector<string> result= single_words(sentence);
for(string& word: result)
cout<<word<<" ";
return 0;
}

How to check if a string ends with 'ed' in C++;

How to write a program that reads 5 strings from user input and prints only those strings that end with the letter ‘ed’ in C++. Need help!
The solution is rather straightforward.
First we define a container that can contain 5 std::string. For that we use a std::vector together with a constructor to reserve space for the 5 elements.
Then we copy 5 strings from the console (from user input) into the vector.
And, last, we copy elements out of the std::vector to std::cout, if the strings end with "ed".
Because of the simplicity of the program, I cannot explain much more . . .
Please see.
#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <iterator>
constexpr size_t NumberOfTexts = 5U;
int main()
{
// Define a container that can hold 5 strings
std::vector<std::string> text(NumberOfTexts);
// Read 5 strings from user
std::copy_n(std::istream_iterator<std::string>(std::cin), NumberOfTexts, text.begin());
// Print the strings with ending "ed" to display
std::copy_if(text.begin(), text.end(), std::ostream_iterator<std::string>(std::cout,"\n"), [](const std::string& s){
return s.size()>=2 && s.substr(s.size()-2) == "ed";
});
return 0;
}
Simple solution,
#include<iostream>
using namespace std;
bool endsWith(const std::string &mainStr, const std::string &toMatch)
{
if(mainStr.size() >= toMatch.size() &&
mainStr.compare(mainStr.size() - toMatch.size(), toMatch.size(), toMatch) == 0)
return true;
else
return false;
}
int main()
{
string s[5];
for(int i=0;i<5;i++)
{
cin>>s[i];
}
for(int i=0;i<5;i++)
{
if(endsWith(s[i],"ed"))
cout<<s[i]<<endl;
}
}
Hope This might Helps:)

How to delete part of a string c++ [duplicate]

I got a string and I want to remove all the punctuations from it. How do I do that? I did some research and found that people use the ispunct() function (I tried that), but I cant seem to get it to work in my code. Anyone got any ideas?
#include <string>
int main() {
string text = "this. is my string. it's here."
if (ispunct(text))
text.erase();
return 0;
}
Using algorithm remove_copy_if :-
string text,result;
std::remove_copy_if(text.begin(), text.end(),
std::back_inserter(result), //Store output
std::ptr_fun<int, int>(&std::ispunct)
);
POW already has a good answer if you need the result as a new string. This answer is how to handle it if you want an in-place update.
The first part of the recipe is std::remove_if, which can remove the punctuation efficiently, packing all the non-punctuation as it goes.
std::remove_if (text.begin (), text.end (), ispunct)
Unfortunately, std::remove_if doesn't shrink the string to the new size. It can't because it has no access to the container itself. Therefore, there's junk characters left in the string after the packed result.
To handle this, std::remove_if returns an iterator that indicates the part of the string that's still needed. This can be used with strings erase method, leading to the following idiom...
text.erase (std::remove_if (text.begin (), text.end (), ispunct), text.end ());
I call this an idiom because it's a common technique that works in many situations. Other types than string provide suitable erase methods, and std::remove (and probably some other algorithm library functions I've forgotten for the moment) take this approach of closing the gaps for items they remove, but leaving the container-resizing to the caller.
#include <string>
#include <iostream>
#include <cctype>
int main() {
std::string text = "this. is my string. it's here.";
for (int i = 0, len = text.size(); i < len; i++)
{
if (ispunct(text[i]))
{
text.erase(i--, 1);
len = text.size();
}
}
std::cout << text;
return 0;
}
Output
this is my string its here
When you delete a character, the size of the string changes. It has to be updated whenever deletion occurs. And, you deleted the current character, so the next character becomes the current character. If you don't decrement the loop counter, the character next to the punctuation character will not be checked.
ispunct takes a char value not a string.
you can do like
for (auto c : string)
if (ispunct(c)) text.erase(text.find_first_of(c));
This will work but it is a slow algorithm.
Pretty good answer by Steve314.
I would like to add a small change :
text.erase (std::remove_if (text.begin (), text.end (), ::ispunct), text.end ());
Adding the :: before the function ispunct takes care of overloading .
The problem here is that ispunct() takes one argument being a character, while you are trying to send a string. You should loop over the elements of the string and erase each character if it is a punctuation like here:
for(size_t i = 0; i<text.length(); ++i)
if(ispunct(text[i]))
text.erase(i--, 1);
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main() {
string str = "this. is my string. it's here.";
transform(str.begin(), str.end(), str.begin(), [](char ch)
{
if( ispunct(ch) )
return '\0';
return ch;
});
}
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s;//string is defined here.
cout << "Please enter a string with punctuation's: " << endl;//Asking for users input
getline(cin, s);//reads in a single string one line at a time
/* ERROR Check: The loop didn't run at first because a semi-colon was placed at the end
of the statement. Remember not to add it for loops. */
for(auto &c : s) //loop checks every character
{
if (ispunct(c)) //to see if its a punctuation
{
c=' '; //if so it replaces it with a blank space.(delete)
}
}
cout << s << endl;
system("pause");
return 0;
}
Another way you could do this would be as follows:
#include <ctype.h> //needed for ispunct()
string onlyLetters(string str){
string retStr = "";
for(int i = 0; i < str.length(); i++){
if(!ispunct(str[i])){
retStr += str[i];
}
}
return retStr;
This ends up creating a new string instead of actually erasing the characters from the old string, but it is a little easier to wrap your head around than using some of the more complex built in functions.
I tried to apply #Steve314's answer but couldn't get it to work until I came across this note here on cppreference.com:
Notes
Like all other functions from <cctype>, the behavior of std::ispunct
is undefined if the argument's value is neither representable as
unsigned char nor equal to EOF. To use these functions safely with
plain chars (or signed chars), the argument should first be converted
to unsigned char.
By studying the example it provides, I am able to make it work like this:
#include <string>
#include <iostream>
#include <cctype>
#include <algorithm>
int main()
{
std::string text = "this. is my string. it's here.";
std::string result;
text.erase(std::remove_if(text.begin(),
text.end(),
[](unsigned char c) { return std::ispunct(c); }),
text.end());
std::cout << text << std::endl;
}
Try to use this one, it will remove all the punctuation on the string in the text file oky.
str.erase(remove_if(str.begin(), str.end(), ::ispunct), str.end());
please reply if helpful
i got it.
size_t found = text.find('.');
text.erase(found, 1);