As you can see from the title I want to change lowercase charachter in word to uppercase and vice versa. Also I need to use struct object (in my case name). I have a problem when I change charachter from lowercase to uppercase it only changes in the first word not in the second,third and so on. I am also reading words from file
Here is the input file
Aayak Audi
Ahmed Golf7
Samed Golf5
Here is the code
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <cctype>
using namespace std;
struct pismaStr
{
string ime;
string objekat;
};
void malaVelikaSlova (string name)
{
for (int i = 0; i < name.length()-1; i++)
{
if (name.at(i) >= 'A' && name.at(i) <= 'Z')
name.at(i) += 32;
else if (name.at(i) >= 'a' && name.at(i) <= 'z')
name.at(i) -= 32;
cout << name;
break;
}
}
int main()
{
ifstream pismo;
pismo.open("pismo.txt");
ofstream novoPismo;
novoPismo.open("novaSlova.txt");
pismaStr stvari[200];
int brojStvari = 0;
while(pismo >> stvari[brojStvari].ime >> stvari[brojStvari].objekat)
{
brojStvari++;
}
for (int i = 0; i < brojStvari; i++)
{
vector <pismaStr> vec = {pismaStr{stvari[i].ime}};
for (auto obj : vec)
{
malaVelikaSlova (obj.ime);
}
}
Here is the output:
aayak
ahmed
samed
It was:
Aayak
ahmed
samed
I want it to look like this
aAYAK
sAMED
aHMED
How can I fix this? Any tips?
but it will be an issue, is this line
for (int i = 0; i < name.length()-1; i++)
This will loop from name[0]
to name[name.length() - 2]
. The std::string::length
returns the number of usable characters. It does not include the null terminator, so you don't need to subtract 1. It should be
for (int i = 0; i < name.length(); i++)
is the break
statement at the end of your loop (indentation added for clarity)
for (int i = 0; i < name.length()-1; i++)
{
if (name.at(i) >= 'A' && name.at(i) <= 'Z')
name.at(i) += 32;
else if (name.at(i) >= 'a' && name.at(i) <= 'z')
name.at(i) -= 32;
cout << name;
break; // <--- this exits the loop entirely
}
Your break;
tells the program to exit the loop immediately. No further iterations of the loop are performed. Your cout
statement is also within the loop. Once you do get the loop running for each iteration, you'll output each step of the transformation. To only output it once (at the end) you put it outside of the loop. If you want to loop over every character (and you do), your final code looks like
void malaVelikaSlova (string name)
{
for (int i = 0; i < name.length() - 1; i++)
{
if (name.at(i) >= 'A' && name.at(i) <= 'Z')
name.at(i) += 32;
else if (name.at(i) >= 'a' && name.at(i) <= 'z')
name.at(i) -= 32;
}
cout << name;
}
You don't need to do bounds checking on your string
indexes, since you're looping based on the string
length, and it's not changing, so you don't need to extra overhead of std::string::at
. You can just use the index operator:
// name.at(i); // <-- no need to do this anywhere
name[i] // <-- slightly faster
Since you're applying some operation to each element (character) in your container (string), this is a great candidate for std::transform
, from the <algorithm>
library. I'm also using a lambda expression here, which is a great too from C++ to get familiar with.
https://en.cppreference.com/w/cpp/algorithm/transform
https://en.cppreference.com/w/cpp/language/lambda
void malaVelikaSlova (string name)
{
std::transform(
name.begin(),
name.end(),
[](char c) -> char
{
if (c >= 'A' && c <= 'Z')
return c + 32;
if (c >= 'a' && c <= 'z')
return c - 32;
return c; // <-- for all other characters
}
);
std::cout << name << "\n";
}
You could even take advantage of the std::isupper
, std::islower
, std::toupper
, and std::tolower
functions to make your code more explicit. Note that std::string
is an alias for std::basic_string<char>
(its value type is char
), the upper
and lower
functions operate on unsigned char
s, so you'll need to convert the char
s to unsigned char
s:
https://en.cppreference.com/w/cpp/string/basic_string
https://en.cppreference.com/w/cpp/string/byte/tolower
https://en.cppreference.com/w/cpp/string/byte/toupper
https://en.cppreference.com/w/cpp/string/byte/isupper
https://en.cppreference.com/w/cpp/string/byte/islower
void malaVelikaSlova (string name)
{
std::transform(
name.begin(),
name.end(),
[](unsigned char c) -> unsigned char // <-- must convert to unsigned to be safe with upper/lower functions
{
if std::isupper(c) return std::tolower(c);
if std::islower(c) return std::toupper(c);
return c; // <-- for all other characters
}
);
std::cout << name << "\n";
}