Convert lowercase to uppercase using ASCII - c

I am trying to convert all lowercase to uppercase letter, using the ASCII table! It is very easy to deal and i have figured out the code. Problem is, that if there is a space between the words, then the program will only change the first word and after the space it will not print anything.
Example
Word: Andreas Gives: ANDREAS
Word: TeSt123Ha Gives: TEST123HA
BUT!!!
Word: Hello 45 Gives: HELLO
after the space it prints nothing!
I know that the space in ASCII table is equal to 32, and in my code i tell the program that if the current code that you are reading is not between 97 and 122, then don't perform any changes!
But it is still not working!
char currentletter;
int i;
for (i=0; i<49; i++)
{
currentletter = str[i];
if ((currentletter > 96) && (currentletter < 123))
{
char newletter;
newletter = currentletter - 32;
str[i] = newletter;
}
else
{
str[i] = currentletter;
}
}
printf("%s\n", str);

flipping the 5th lowest bit should help.
Each lowercase letter is 32 + uppercase equivalent. This means simply flipping the bit at position 5 (counting from least significant bit at position 0) inverts the case of a letter.
https://web.stanford.edu/class/cs107/lab1/practice.html
char *str;
int str_size = sizeof(str);
for(int i=0; i<str_size;i++){
if((str[i]>96) && (str[i]<123)) str[i] ^=0x20;
}

You have mentioned in one of the comments that you use scanf("%s", str); to get the string. The problem is that %s will stop scanning once it finds a whitespace character. In your case, it stops scanning when it sees the space character.
Use fgets() if you want to scan one whole line:
fgets(str, sizeof(str), stdin);
Once thing to note here is that fgets will scan in the newline character into the string as well.
Your code can be simplified to:
for (int i = 0; str[i] != '\0'; i++) // Loop until the NUL-terminator
{
if ((str[i] >= 'a') && (str[i] <= 'z')) // If the current character is a lowercase alphabet
str[i] = str[i] - ('a' - 'A'); // See the ASCII table to understand this:
// http://www.asciitable.com/index/asciifull.gif
}
printf("%s\n", str);
Or a more easier way would be to use tolower from ctype.h:
#include <ctype.h>
for(int i = 0; str[i] != '\0'; i++) // Loop until the NUL-terminator
{
str[i] = tolower(str[i]); // Convert each character to lowercase (It does nothing if the character is not an alphabet)
}
printf("%s\n", str);

I gave it a try using STL and a Lambda just for fun:
string input = "";
getline(cin, input);
transform(input.begin(), input.end(), input.begin(), [](char c) { return (c > 96 && c < 123) ? c ^= 0x20 : c; });
copy(input.begin(), input.end(), ostream_iterator<char>(cout, " "));
I compiled and tested with c++ 17 in Visual Studio 2019,
and did not perform exhaustive testing!

Related

Counting the number of words, numbers, uppercase and lowercase characters

I am a beginner programmer and there was this exercise I found that said:
Write a string of characters and determine the number of words, numbers, uppercase and lowercase characters and spaces.
I thought I built a decent enough program and it works, kind of!
The problem is that when I try to run it the result is not entirely correct.
For example; When I write: HI MY name is Ani 1 1 2 a
it says that
Spaces = 8. Correct here
Numbers = 3. Correct here as well
Upper Case characters = 4. It should be 5
Lower Case characters = 7. It should be 9
Words = 26. Which is completely wrong
As for the words, I found a new way to count them. By counting spaces+1, but I want to count them correctly.
Is it possible to point out the mistakes?
This is what I have done so far
int main() {
char str[1000+1];
int words = 0;
int numbers = 0;
int uppercharacters = 0;
int lowercharacters = 0;
int spaces = 0;
int i;
printf("Please enter the string of characters: ");
gets(str);
for (i = 0; str[i] != '\0'; i++) {
if (str[i] > 'a' && str[i] < 'z')
lowercharacters++;
else if (str[i] > 'A' && str[i] < 'Z')
uppercharacters++;
else if (str[i] == ' ')
spaces++;
else if (str[i] > '0' && str[i] < '9')
numbers++;
else if (str[i] == ' ' && str[i + 1] != ' ');
words++;
}
printf("Spaces = %d\n", spaces);
printf("numbers = %d\n", numbers);
printf("Upper Case characters = %d\n", uppercharacters);
printf("Lower Case characters = %d\n", lowercharacters);
printf("Words = %d\n", words + 1);
return 0;
}
As for the words, I found a new way to count them. By counting spaces+1, but I want to count them correctly.
The code fails due to ; at the end of the else if().
Tip: Good compilers with all warnings enabled will warn about that.
Save time, and enable all warnings.
// v !!!
else if(str[i]==' ' && str[i+1]!=' ');
words++;
Even if corrected to
else if(str[i]==' ' && str[i+1]!=' ')
words++;
it still fails with input like " abc" (lead space) reports as two words.
Instead, count the occurrences of a letter following a non-letter.
char previous = '\n';
for(i=0; str[i] != '\0'; i++) {
if (isalpha(str[i]) && !isalpha(previous)) {
words++;
}
previous = str[i];
}
Make your own helper functions if the standard ones, like is...(), are not allowed.
You should use if(str[i]>='a' && str[i]<='z') instead of if(str[i]>'a' && str[i]<'z'). You don't want to exclude the characters z and a from being tested.
For the counting words part, notice that there is one misplaced semicolon after your last else if statement. The number of words won't be 100% correct if you fix that typo, but you might be able to work from there :)

C program to capitalize a word inside quotation marks

I need to build a function that gets an input and capitalizes only the first letter, doesn't print numbers, capitalizes after a . for a new sentence, and capitalizes all words between a double quotation marks ".
This is what I got until now:
#include <stdio.h>
#define MAX 100
int main()
{
char str[MAX] = { 0 };
int i;
//input string
printf("Enter a string: ");
scanf("%[^\n]s", str); //read string with spaces
//capitalize first character of words
for (i = 0; str[i] != '\0'; i++)
{
//check first character is lowercase alphabet
if (i == 0)
{
if ((str[i] >= 'a' && str[i] <= 'z'))
str[i] = str[i] - 32; //subtract 32 to make it capital
continue; //continue to the loop
}
if (str[i] == '.')//check dot
{
//if dot is found, check next character
++i;
//check next character is lowercase alphabet
if (str[i] >= 'a' && str[i] <= 'z')
{
str[i] = str[i] - 32; //subtract 32 to make it capital
continue; //continue to the loop
}
}
else
{
//all other uppercase characters should be in lowercase
if (str[i] >= 'A' && str[i] <= 'Z')
str[i] = str[i] + 32; //subtract 32 to make it small/lowercase
}
}
printf("Capitalize string is: %s\n", str);
return 0;
}
I cant find a way to remove all numbers from input and convert all lowercase to uppercase inside a " plus code for not printing numbers if user input them.
if I input
I am young. You are young. All of us are young.
"I think we need some help. Please" HELP. NO, NO NO,
I DO NOT
NEED HELP
WHATSOEVER.
"Today’s date is
15/2/2021"...
I am 18 years old, are you 20 years old? Maybe 30 years?
output:
I am young. You are young. All of us are young.
"I THINK WE NEED SOME HELP. PLEASE" help. No, no no,
i do not
need help
whatsoever.
"TODAY’S DATE IS
//"...
I am years old, are you years old? maybe years?
The C standard library provides a set of functions, in ctype.h, that will help you
Of particular interest, would be:
isdigit() - returns true if digit
isalpha() - returns true if alphabet character
isalnum() - returns true if alpha/numeric character
islower() - returns true if lower case character
isupper() - returns true if upper case character
tolower() - converts character to lower case
toupper() - converts character to upper case
So, for example, you could replace the test/modify with:
if ( islower( str[i] ) )
{
str[i] = toupper( str[i] );
}
Pedantically, islower() and toupper() return an unsigned int but that's a separate matter...
You can remove letters from a string if you keep two indices, one for reading and one for writing. The following loop will remove all digits from a string:
int j = 0; // writing index, j <= i
int i; // reading index
for (i = 0; str[i]; i++) {
int c = (unsigned char) str[i];
if (!isdigit(c)) str[j++] = c;
}
str[j] = '\0';
(I've used to character classification functions from <ctype.h> mentioned in Andrew' answer.)
This is safe, because j will always be smaller or equal to i. Don't forget to mark the end of the filtered string with the nullterminator, '\0'. You can combine this filtering with your already existing code for replacing characters.
In your code, you capitalize letters only if they are directly behind a full stop. That's usually not the case, there's a space between full stop and the next word. It's better to establish a context:
shift: capitalize the next letter (beginning or after full stop.)
lock: capitalize all letters (inside quotation marks.)
When you read a letter, decide whether to capitalize it or not depending of these two states.
Putting the filtering and the "shift context§ together:
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char str[] = "one. two. THREE. 4, 5, 6. \"seven\", eight!";
int shift = 1; // Capitalize next letter
int lock = 0; // Capitalize all letters
int j = 0; // writing index, j <= i
int i; // reading index
for (i = 0; str[i]; i++) {
int c = (unsigned char) str[i];
if (isdigit(c)) continue;
if (isalpha(c)) {
if (shift || lock) {
str[j++] = toupper(c);
shift = 0;
} else {
str[j++] = tolower(c);
}
} else {
if (c == '"') lock = !lock;
if (c == '.') shift = 1;
str[j++] = c;
}
}
str[j] = '\0';
puts(str);
printf("(length: %d)\n", j);
return 0;
}
In order to remove some characters, you should use 2 index variables: one for reading and one for writing back to the same array.
If you are allowed to use <ctype.h>, it is a much more portable and efficient way to test character types.
Also do not use scanf() with protection against buffer overflow. It is as bad as using gets(). Given the difficulty in specifying the maximum number of bytes to store into str, you should use fgets() instead of scanf().
Here is a modified version:
#include <ctype.h>
#include <stdio.h>
#define MAX 100
int main() {
char str[MAX];
int i, j;
unsigned char last, inquote;
//input string
printf("Enter a string: ");
if (!fgets(str, sizeof str, stdin)) { //read string with spaces
// empty file
return 1;
}
last = '.'; // force conversion of first character
inquote = 0;
//capitalize first character of words
for (i = j = 0; str[i] != '\0'; i++) {
unsigned char c = str[i];
//discard digits
if (isdigit(c)) {
continue;
}
//handle double quotes:
if (c == '"') {
inquote ^= 1;
}
//upper case letters after . and inside double quotes
if (last == '.' || inquote) {
str[j++] = toupper(c);
} else {
str[j++] = tolower(c);
}
if (!isspace(c) && c != '"') {
// ignore spaces and quotes for the dot rule
last = c;
}
}
str[j] = '\0'; // set the null terminator in case characters were removed
printf("Capitalized string is: %s", str);
return 0;
}

Why would a character array be unchanged after a for-loop?

I have built a function with the goal of taking text that is fed from elsewhere in the program and removing all whitespace and punctuation from it. I'm able to remove whitespace and punctuation, but the changes don't stay after they are made. For instance, I put the character array/string into a for-loop to remove whitespace and verify that the whitespace is removed by printing the current string to the screen. When I send the string through a loop to remove punctuation, though, it acts as though I did not remove whitespace from earlier. This is an example of what I'm talking about:
Example of output to screen
The function that I'm using is here.
//eliminates all punctuation, capital letters, and whitespace in plaintext
char *formatPlainText(char *plainText) {
int length = strlen(plainText);
//turn capital letters into lower case letters
for (int i = 0; i < length; i++)
plainText[i] = tolower(plainText[i]);
//remove whitespace
for (int i = 0; i < length; i++) {
if (plainText[i] == ' ')
plainText[i] = plainText[i++];
printf("%c", plainText[i]);
}
printf("\n\n");
//remove punctuation from text
for (int i = 0; i < length; i++) {
if (ispunct(plainText[i]))
plainText[i] = plainText[i++];
printf("%c", plainText[i]);
}
}
Any help as to why the text is unchanged after if exits the loop would be appreciated.
Those for loops are not necessary. Your function can be modified as follows and I commented where I made those changes:
char* formatPlainText(char *plainText)
{
char *dest = plainText; //dest to hold the modified version of plainText
while ( *plainText ) // as far as *plainText is not '\0'
{
int k = tolower(*plainText);
if( !ispunct(k) && k != ' ') // check each char for ' ' and any punctuation mark
*dest++ = tolower(*plainText); // place the lower case of *plainText to *dest and increment dest
plainText++;
}
*dest = '\0'; // This is important because in the while loop we escape it
return dest;
}
From main:
int main( void ){
char str[] = "Practice ????? &&!!! makes ??progress!!!!!";
char * res = formatPlainText(str);
printf("%s \n", str);
}
The code does convert the string to lower case, but the space and punctuation removal phases are broken: plainText[i] = plainText[i++]; has undefined behavior because you use i and modify it elsewhere in the same expression.
Furthermore, you do not return plainText from the function. Depending on how you use the function, this leads to undefined behavior if you store the return value to a pointer and later dereference it.
You can fix the problems by using 2 different index variables for reading and writing to the string when removing characters.
Note too that you should not use a length variable as the string length changes in the second and third phase. Texting for the null terminator is simpler.
Also note that tolower() and ispunct() and other functions from <ctype.h> are only defined for argument values in the range 0..UCHAR_MAX and the special negative value EOF. char arguments must be cast as (unsigned char) to avoid undefined behavior on negative char values on platforms where char is signed by default.
Here is a modified version:
#include <ctype.h>
//eliminate all punctuation, capital letters, and whitespace in plaintext
char *formatPlainText(char *plainText) {
size_t i, j;
//turn capital letters into lower case letters
for (i = 0; plainText[i] != '\0'; i++) {
plainText[i] = tolower((unsigned char)plainText[i]);
}
printf("lowercase: %s\n", plainText);
//remove whitespace
for (i = j = 0; plainText[i] != '\0'; i++) {
if (plainText[i] != ' ')
plainText[j++] = plainText[i];
}
plainText[j] = '\0';
printf("no white space: %s\n", plainText);
//remove punctuation from text
for (i = j = 0; plainText[i] != '\0'; i++) {
if (!ispunct((unsigned char)plainText[i]))
plainText[j++] = plainText[i];
}
plainText[j] = '\0';
printf("no punctuation: %s\n", plainText);
return plainText;
}

C Rotating String Program?

#include <stdio.h>
int main()
{
int rotation, i=0;
char str[80]={0};
printf("Enter Text: ");
scanf("%[^\n]", str);
printf("\"");
printf("Enter Rotation: ");
scanf("%i", &rotation);
while(str[i])
{
if (str[i] >= 'a' && str[i] <= 'z')
printf("%c\n", 'a' + (str[i] - 'a' + rotation)%26);
else
printf("%c\n", str[i]);
i++;
}
return 0;
}
Have a hard time understanding this line of code (printf("%c\n", 'a' + (str[i] - 'a' + rotation)%26); )
Can anyone just write a brief explanation quickly it would help me
The program is taking the user's input text and on a per character basis rotating it through the alphabet based on the number entered. It works because of the ASCII table.
The line in question takes the character a user entered, offsets it by 'a' (which equals 91 in ASCII), adds in the rotation factor then performs modulo 26 on the result (how many characters are there in the alphabet again?) to make sure the result is still a lowercase character.
I bet you could find a good way to break this program :)

How do i cycle through each letter in a string?

#include <stdio.h>
int main()
#include <stdio.h>
int main()
{
char msg[31] = {'\0'};
char encrypted[31] = {'\0'};
int key;
printf("Please enter a message under 30 characters: ");
fgets(msg, 31, stdin);
printf("Please enter an encryption key: ");
scanf("%d", &key);
int i = 0;
while (msg[i] && ('a' <= msg[i] <= 'z' || 'A' < msg[i] < 'Z'))
{
encrypted[i] = (msg[i] + key);
i++;
}
printf("%s\n", msg);
printf("%d\n", key);
printf("%s\n", encrypted);
}
Okay i've got my code to increment the characters but i don't know how to make it ignore special characters and spaces. Also how do i use % to loop back to 'a' and 'A'?
Thank you.
You just need a simple for loop:
for (int i = 0; i < 31; i++)
{
// operate on msg[i]
}
If you didn't know the length of the string to begin with, you might prefer a while loop that detects the null terminator:
int i = 0;
while (msg[i])
{
// operate on msg[i]
i++;
}
Your fgets and scanf are probably fine, but personally, I would be consistent when reading input, and fgets for it all. Then you can sscanf to get key out later.
scanf and fgets seem fine in this situation the way you've used them.
In C, a string is just an array of characters. So, you access each element using a for loop and array indexing:
for (int i = 0; i < strlen(str); i++) {
char thisChar = str[i];
//Do the processing for each character
}
You can perform arithmetic on thisChar as necessary, but be careful not to exceed 255. You might want to put a check on key to ensure it doesn't get too big.
Getting a string from scanf:
char msg[31];
scanf("%30s", msg);
OR (less efficient, because you have to fill the array with 0s first)
char msg[31] = { 0 };
scanf("%30c", msg);
Iterating a string is as easy a for loop (be sure to use c99 or c11)
int len = strlen(msg);
for(int i = 0; i < len; i++) {
char current = msg[i];
//do something
msg[i] = current;
}
"Encrypting" (i.e. ciphering) a character require a few steps
Determine if we have an uppercase character, lowercase character, or non-alphabetic character
Determine the position in the alphabet, if alphabetic.
Update the position, using the modulus operator (%)
Correct the position, if alphabetic
I could give you the code here, but then you wouldn't learn anything from doing it yourself. Instead, I encourage you to implement the cipher based on the steps I provided above.
Note that you can do things like:
char c = 'C';
char e = 'E' + 2;
char lower_c = 'C' - 'A' + 'a';

Resources