I am trying to check if the whole word is upper case, if this is true it should return true, else return false.
My current code is:
#include "UpperCaseFilter.h"
#include "ReadFilteredWords.h"
#include "ReadWords.h"
#include <locale>
bool UpperCaseFilter::filter(string word) {
if(!word.empty()) {
for(int i = 0; i < word.length(); i++) {
if(isupper(word[i])) {
return true;
}
else {
return false;
}
}
}
}
The problem with this code is, if i have for example HeLLO, it will return true because my last character is true. How would I only return true if the whole string is true. I did it using a counter method but it is not the most efficient.
I also tried using the all_of method but I think I dont have the correct compiler version because it says all_of isn't defined (Even with correct imports).
I'm not sure what other approaches there are to this.
Alternatively utilize the std::all_of function in combination with std::isupper in predicate:
#include <iostream>
#include <string>
#include <algorithm>
int main() {
std::string s = "HELLo";
if (std::all_of(s.begin(), s.end(), [](unsigned char c){ return std::isupper(c); })) {
std::cout << "Is uppercase." << '\n';
} else {
std::cout << "Is not uppercase." << '\n';
}
}
Used as part of a function:
bool isUpper(const std::string& s) {
return std::all_of(s.begin(), s.end(), [](unsigned char c){ return std::isupper(c); });
}
bool is_all_upper(const std::string& word)
{
for(auto& c: word)
if(!std::isupper(static_cast<unsigned char>(c)))
return false;
return true;
}
I assume that, if the string is empty, it can be considered all-uppercase.
You shouldn't have two return conditions inside your loop. Rather, you can use the loop to find problems and, if there are no problems, you'll escape the loop and can tell the user that everything was alright at the end.
In the comments you say "i believe it doesn't need to return anything if the string is empty"; however, a function with a return type, such as this one always returns something. If you don't specify a return value it will give you one, whether you like it or not. Therefore, you must decide what the output should be for every conceivable input. Accordingly, I've added an if statement that emphasizes the special condition of an empty string.
#include "UpperCaseFilter.h"
#include "ReadFilteredWords.h"
#include "ReadWords.h"
#include <locale>
bool UpperCaseFilter::filter(const string &word) {
if(word.empty()) //You'll need to do the right thing here
return true;
//Even if the right thing to do were to return true, so that
//the check above would be redundant, you'd want to leave a
//comment here pointing out that you've handled the special case
for(size_t i = 0; i < word.length(); i++)
if(!isupper(static_cast<unsigned char>(word[i])))
return false;
return true;
}
Note that your previous function signature was:
bool UpperCaseFilter::filter(string word) {
I've changed this to:
bool UpperCaseFilter::filter(const string &word) {
The const guarantees that the function will not alter word and the & symbol passes the string to the function without copying it. This makes the function faster and saves memory.
#include "UpperCaseFilter.h"
#include "ReadFilteredWords.h"
#include "ReadWords.h"
#include <locale>
bool UpperCaseFilter::filter(string word)
{
int k=0;
if(!word.empty())
{
for(int i = 0; i < word.length(); i++)
{
if(isupper(word[i]))
k++;
}
}
if(k==word.length())
return true;
else
return false; //this will return false even when word length is 0
}
its more simple now provided if you have done other things right this would run.
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
string str;
cin >> str;
bool flag = false;
int i = 0;
while(str[i])
{
if(isupper(str[i]))
{
flag = true;
}
if(!(isupper(str[i])))
{
flag = false;
break;
}
i++;
}
if(flag == false)
cout << "false" << endl;
else
cout << "true" << endl;
}
#include <iostream>
#include <string>
#include <boost/algorithm/string.hpp>
bool IsAllUpperString(string str)
{
if(boost::to_upper_copy(str)== str) return true;
return false;
}
Related
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
}
I am a beginner at coding, and was trying this question that replaces all repetitions of a letter in a string with a hyphen: i.e ABCDAKEA will become ABCD-KE-.I used the switch loop and it works, but i want to make it shorter and maybe use recursion to make it more effective. Any ideas?
#include<iostream>
#include<string.h>
using namespace std;
int main()
{
char x[100];
int count[26]={0}; //initialised to zero
cout<<"Enter string: ";
cin>>x;
for(int i=0; i<strlen(x); i++)
{
switch(x[i])
{
case 'a':
{
if((count[0]++)>1)
x[i]='-';
}
case 'b':
{
if((count[1]++)>1)
x[i]='-';
}
case 'c':
{
if((count[2]++)>1)
x[i]='-';
}
//....and so on for all alphabets, ik not the cutest//
}
}
Iterate through the array skipping whitespace, and put characters you've never encountered before in std::set, if you find them again you put them in a duplicates std::set if you'd like to keep track of how many duplicates there are, otherwise change the value of the original string at that location to a hyphen.
#include <iostream>
#include <string>
#include <cctype>
#include <set>
int main() {
std::string s("Hello world");
std::set<char> characters;
std::set<char> duplicates;
for (std::string::size_type pos = 0; pos < s.size(); pos++) {
char c = s[pos];
// std::isspace() accepts an int, so cast c to an int
if (!std::isspace(static_cast<int>(c))) {
if (characters.count(c) == 0) {
characters.insert(c);
} else {
duplicates.insert(c);
s[pos] = '-';
}
}
}
return 0;
}
Naive (inefficient) but simple approach, requires at least C++11.
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
std::string f(std::string s)
{
auto first{s.begin()};
const auto last{s.end()};
while (first != last)
{
auto next{first + 1};
if (std::isalpha(static_cast<unsigned char>(*first)))
std::replace(next, last, *first, '-');
first = next;
}
return s;
}
int main()
{
const std::string input{"ABCDBEFKAJHLB"};
std::cout << f(input) << '\n';
return 0;
}
First, notice English capital letters in ASCII table fall in this range 65-90. Casting a capital letter static_cast<int>('A') will yield an integer. If after casing the number is between 65-90, we know it is a capital letter. For small letters, the range is 97-122. Otherwise the character is not a letter basically.
Check create an array or a vector of bool and track the repetitive letters. Simple approach is
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
string str("ABCDAKEAK");
vector<bool> vec(26,false);
for(int i(0); i < str.size(); ++i){
if( !vec[static_cast<int>(str[i]) - 65] ){
cout << str[i];
vec[static_cast<int>(str[i]) - 65] = true;
}else{
cout << "-";
}
}
cout << endl;
return 0;
}
Note: I assume the input solely letters and they are capital. The idea is centered around tracking via bool.
When you assume input charactor encode is UTF-8, you can refactor like below:
#include <iostream>
#include <string>
#include <optional>
#include <utility>
std::optional<std::size_t> char_to_index(char u8char){
if (u8'a' <= u8char && u8char <= u8'z'){
return u8char - u8'a';
}
else if (u8'A' <= u8char && u8char <= u8'A'){
return u8char - u8'A';
}
else {
return std::nullopt;
}
}
std::string repalce_mutiple_occurence(std::string u8input, char u8char)
{
bool already_found[26] = {};
for(char& c : u8input){
if (const auto index = char_to_index(c); index && std::exchange(already_found[*index], true)){
c = u8char;
}
}
return u8input;
}
int main(){
std::string input;
std::getline(std::cin, input);
std::cout << repalce_mutiple_occurence(input, u8'-');
}
https://wandbox.org/permlink/UnVJHWH9UwlgT7KB
note: On C++20, you should use char8_t instead of using char.
I need to write a method for the class "smartReverse" to return a reversed string of the the class's one private string variable: "str". There are some rules to this however:
I must use recursion to create a reversed string.
There cannot be any parameters in the method.
The variable "str" cannot be altered, the method must return a seperate string created inside the method ("rev_str" is my code)
I've been working on this particular method for a couple hours every day since last Wednesday, and I've gotten nowhere. Help is appreciated!
NOTE: this code comes from a test file where the "Recursive" method is just a standalone function in my "main.cpp". There is one string parameter just to simulate it being a method.
string Recursive(string str) {
if (str.length() <= 1) {
return str;
}
else {
string rev_str;
rev_str = rev_str + str.substr(str.length() - 1 -
rev_str.length(), 1);
if (rev_str.length() == str.length()) {
return rev_str;
}
else {
recursive(str);
}
}
}
The only results I've gotten out of my hours is overflow in "rev_str".
Recursion without input parameter sounds pretty senseless but you can use non-static member variables instead:
#include <iostream>
#include <string>
class smartReverse {
std::string str;
std::size_t counter = 0;
std::string recursion() {
if (counter > str.size())
return "";
char c = str[counter];
if (counter == str.size() - 1)
return std::string(1, c);
++counter;
return recursion() + c;
}
public:
smartReverse(std::string s) : str(s) {}
std::string reverse() {
counter = 0;
return recursion();
}
};
int main() {
std::cout << smartReverse("Teststring").reverse() << '\n';
return 0;
}
I don't really see the point of this exercice, but who knows…
Have a great time learning C++, hopefully we will quickly see std::reverse.
#include <string>
#include <iostream>
using namespace std;
string Recursive(string str) {
if (str.length() <= 1) {
return str;
}
else {
string rev_str = str.substr(str.length() - 1, 1);
str.pop_back();
if (str.empty()) {
return rev_str;
}
else {
string back = Recursive(str);
rev_str+= back;
return rev_str;
}
}
}
int main()
{
std::cout<< Recursive(std::string("abcdefghijklmnopqrstuvwxyz"));
}
I get the same string back when I try to reverse it in C++.
I read that recursion is a good way to reverse things. I tried to implement a recursive algorithm by returning the first character of the string and calling the same function with the first character removed until the string has a size of 1. My first function removes the first character of the string and the second function reverses it:
string deleteFirstElement(string input) {
if (input.size() == 1) {
return input;
}
// This loop brings the first element to the last position
for (int i = 0; i < input.size()-1; i++) {
char temp;
temp = input.at(i);
input.at(i) = input.at(i+1);
input.at(i + 1) = temp;
}
input.pop_back(); // Delete last element of the string
return input;
}
string reverseit(string input) {
if (input.size() == 1) {
return input;
}
else {
return input.at(0) + reverseit(deleteFirstElement(input));
}
}
But why do I get the same string back and no reverse?
You get the same string back because you build the same string again.
Using the example of "ABC" you'll see what the function does:
reverseit("ABC") returns 'A' + reverseit("BC")
reverseit("BC") returns 'B' + reverseit("C")
reverseit("C") returns 'C'
You'd want
char firstChar = input.at(0);
return reverseit(deleteFirstElement(input)) + firstChar;
But really you should be looking into another solution. Recursion
reduces readability
is slow
uses lots of stack memory
easily creates hard to debug endless loops
in general it should be avoided if possible. Some solutions are really elegant with it, to be sure, but loops are almost always faster.
change the else part from this
string reverseit(string input) {
if (input.size() == 1) {
return input;
}
else {
return input.at(0) + reverseit(deleteFirstElement(input));
}
}
to this
string reverseit(string input) {
if (input.size() == 1) {
return input;
}
else {
return reverseit(deleteFirstElement(input))+ input.at(0);
}
}
Recursion is not the easy way to reverse things.
Here is the easy way:
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s { "hello" };
reverse(s.begin(), s.end());
cout << s << endl;
}
Here is a recusive solution. It works but is much less reasonable and efficient.
#include <iostream>
#include <string>
using namespace std;
string recursiveReverse(string value, string accum = "")
{
if(value.size() == 0)
{
return accum;
}
else
{
accum += value.back();
value.pop_back();
return recursiveReverse(value, accum);
}
}
int main()
{
string s { "hello" };
s = recursiveReverse(s);
cout << s << endl;
}
If you have boost, this problem basicly boils down:
string reverseit(string input) {
string result(input);
boost::range::reverse(result);
return result;
}
Without boost, you may instead use:
std::reverse(result.begin(), result.end());
As noted, recursion reduced readability of your program and should be reserved for rare cases (usually where another solution is just more complicated).
Really basic question but I can't figure this out. My program checks if a string is unique by setting flags for each ASCII in an array to true if found in the string. It's not working(it compiles, but doesn't give correct answer), and I can't for the life of my figure out why.
The output I get is 0:
main.cpp
#include "main.hpp"
#include <iostream>
bool isUnique(std::string str) {
if(str.length() > 128)
return false;
bool theChars[128];
for(int i = 0; i < str.length(); i++) {
int loc = str.at(i);
if(theChars[loc])
return false;
else
theChars[loc] = true;
}
return true;
}
int main() {
std::string timmy = "abcdefghijklmnop";
std::cout << isUnique(timmy);
return 0;
}
You forgot to initialize the bool array:
bool theChars[128] = {};
The empty initializer means "use the default value" which is zero, aka false for bool.
P.S. Your code produces undefined behavior if you have any character outside [0, 127]. You could fix this by making theChars 256 long and casting the character to uint8_t before indexing. Or use std::array<char, 128> and theChars.at(loc) to throw an exception if out of bounds.
easier way is use set:
#include <iostream>
#include <set>
using namespace std;
bool isUnique(string str) {
set<char>st(str.begin(),str.end());
if(st.size()==str.size())
return true;
return false;
}
int main() {
string timmy = "abcdefghijklmnop";
cout << boolalpha<<isUnique(timmy)<<endl;
timmy = "aaaaabbbcdefghijklmnop";
cout << boolalpha<<isUnique(timmy)<<endl;
return 0;
}
p.s. if not use boolalpha, it will print 1 for true and 0 for false.
std::sort(str.begin(), str.end());
return std::adjacent_find(str.begin(), str.end()) == str.end();
This doesn't use any additional space, and works for any character encoding.