I have an assignment like
the codes must capitilize the first letter after period and put a space.
I wrote a function like that which capitalize the first letter after period.
for (i = 0; str[i] != '\0'; i++)
{
if (i == 0)
{
if ((str[i] >= 'a' && str[i] <= 'z'))
str[i] = str[i] - 32;
continue;
}
if (str[i] == '.' || str[i] == '!' || str[i] == '?')
{
++i;
if (str[i] >= 'a' && str[i] <= 'z')
{
str[i] = str[i] - 32;
continue;
}
}
else
{
if (str[i] >= 'A' && str[i] <= 'Z')
str[i] = str[i] + 32;
}
}
But I couldn't do the putting space part can someone help me pls
Adding spaces in your string means you're final string will contain more characters than the original one.
Thus you'll need to allocate memory, using malloc.
What you can do is:
Get the period count in your string
Deduce the number of spaces you'll have to add
Allocate a new string that is strlen(old_string) + space_count + 1 long
Finally iterate through your old string, copying / modifying each character you want to, and adding a space in the new string when needed
Let me know if it's not clear enough, or if you need more precise informations.
Do not use magic numbers. Use standard functions instead.
passed string has to be modifiable and has enough room to accommodate new spaces.
The function below adds space after characters listed in the after string. If there is a blank space after this character it does not and skips all the blank spaces, then capitalize the first non-blank character. It does not add space if the character listed in after is the last in the string.
char *addSpaceAndCapitalizeAfter(char *str, const char *after)
{
char *wrk = str;
if(str && after)
{
while(*str)
{
if(strchr(after, *str))
{
if(str[1] && !isblank((unsigned char)str[1]) && str[2])
{
memmove(str + 2, str + 1, strlen(str) + 1);
str[1] = ' ';
str++;
}
str++;
while(*str && isblank((unsigned char)*str)) str++;
if(*str) *str = toupper((unsigned char)*str);
}
else
{
str++;
}
}
}
return wrk;
}
int main(void)
{
char str[100] = ",test,string, some, words,";
printf("`%s`\n", addSpaceAndCapitalizeAfter(str, ","));
}
https://godbolt.org/z/ecq1zxqYW
Related
I am trying to capitalize every word in and here is my code:
char *cap_string(char *str)
{
int i;
for (i = 0; str[i] != '\0'; i++)
{
if (i == 0)
{
if (str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
continue;
}
if (str[i] == ' ')
{
++i;
if (str[i] >= 'a' && str[i] <= 'z')
{
str[i] -= 32;
continue;
}
}
else
{
if (str[i] == '.')
{
++i;
if (str[i] >= 'a' && str[i] <= 'z')
{
str[i] -= 32;
continue;
}
}
}
}
return (str);
}
My question is that my code works fine in most cases, but does not function properly if it encounters multiple white spaces. How can I capitalize a word preceded by multiple white spaces?
Change your code to the following:-
char *cap_string(char *str)
{
int i;
for (i = 0; str[i] != '\0'; i++)
{
if (i == 0 || str[i - 1] == ' ' || str[i - 1] == '.' || str[i-1] == '\n')
{
if (str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
}
}
return (str);
}
Testing all cases, using the following code,
#include <stdio.h>
int main()
{
char str[] = "hello world.hello";
printf("%s", cap_string(str));
return 0;
}
returns
Hello World.Hello
I have tried to keep your logic intact and not use any string.h library functions.
You have to keep in mind that the other conditions after the || operator are not checked if the first condition is evaluated as true. So str[-1] never occurs.
The main idea is look at the previous letter to see if the current letter has to upper case. Introduced a constant UPCASE_AFTER so it's easy to add other punctuation marks (say, '!', '?'). Added test case. Refactored for readability.
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#define UPCASE_AFTER " ."
char *cap_string(char *str) {
for (int i = 0; str[i]; i++) {
if (!i || strchr(UPCASE_AFTER, str[i-1])) {
str[i] = toupper(str[i]);
}
}
return str;
}
int main() {
printf("%s\n", cap_string((char []) {"a bb c.d.ee..f."}));
return 0;
}
and it returns:
A Bb C.D.Ee..F.
Here's another alternative:
#include <stdio.h>
// Use standard library routines
// like 'isalpha()', 'toupper'...
// Not all character sets have ASCII's contiguous alphabets.
#include <ctype.h>
char *cap_string( char *str ) {
bool flag = true; // 'state flag' indicating "hunting for lowercase letter"
for( char *cp = str; *cp; cp++ )
if( flag && islower( *cp ) ) {
*cp = (char)toupper( *cp );
flag = false;
}
else
flag = !isalpha( *cp );
return str; // 'return' is not a function call
}
int my_main() {
char str[] = "what? now is the time (we say sometimes) to learn C.";
printf( "%s\n", cap_string( str ) );
return 0; // 'return' is not a function call
}
Output
What? Now Is The Time (We Say Sometimes) To Learn C.
I have this exercise who capitalize the first character in given sentence.Please i can't understood what "i - 1" and str[i - 1] means
#include <stdio.h>
char* ft_strcapitalize(char *str)
{
int i;
i = 0;
while (str[i])
{
if ((i - 1 == 0 && str[i] != ' ')
|| (str[i - 1] >= 'a' && str[i - 1] <= 'z')
|| (str[i - 1] >= 'A' && str[i - 1] <= 'Z')
|| (str[i - 1] >= '1' && str[i - 1] <= '9'))
{
}
else if (str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
i++;
}
return (str);
}
int main(void)
{
char s[] = "salut, comment tu vas ? 42mots quarante-deux; cinquante+et+un";
ft_strcapitalize(s);
printf("%s", s);
}
Please i can't understood what "i - 1" and str[i - 1] means
str[i - 1] attempts to access the previous character in the string - the one before str[i]. It is bad code to use when i==0.
Create a function that capitalizes the first letter of each word and transforms all other letters to lowercase
Keep a state variable that identifies the next character may start a sentence. Use character handling functions from <ctype.h>.
#include <ctype.h>
#include <stdbool.h>
char* ft_strcapitalize(char *str) {
size_t i = 0;
bool start = true;
while (str[i]) {
if (start && isalpha(str[i])) {
str[i] = toupper(str[i]);
start = false;
} else {
str[i] = tolower(str[i]);
// TBD: Adjust 'start' detection as needed.
if (str[i] == '.' || str[i] == '?' || str[i] == '!') {
start = true;
}
}
i++;
}
return str;
}
The code accepts a character string str as parameter, finds the largest character from the string, and moves it to the beginning of the string.
Example 1 (Single instance of large char)
Input: adebc
Output:eadbc
Example 2 (Multiple instance of large char)
Input: agfcdeg
Output:gafcdeg
Code
void maxCharToFront(char *str)
{
int large, i = 0;
char first;
large = str[i];
/* Find largest character */
while (str[i] != '\0')
{
if ((str[i] >= 'a' && str[i] <= 'z') ||
(str[i] >= 'A' && str[i] <= 'Z'))
{
if (str[i] > large)
{
large = str[i];
}
}
i++;
}
for(int i = 0; i < strlen(str); i++)
str[i] = str[i+1];
/*Move largest character to the front*/
first = str[0];
str[0]=large;
str[1] = first;
}
However instead of moving the largest char to the front it and leaving the rest intact, my code merely replaces the first character with the code.
Input: adebc
Current output:eebc
How do I improve this?
Consider the following suggestions:
You just need to store the position of largest char.
2nd for loop does not always need to loop till the end of the string.
You don't need to swap the first and largest char since you have adjusted the string, you can directly store the largest char in 0th location.
Sample code
void maxCharToFront(char *str)
{
int i = 0;
int pos=0;
/* Find largest character */
while (str[i] != '\0')
{
if ((str[i] >= 'a' && str[i] <= 'z') ||
(str[i] >= 'A' && str[i] <= 'Z'))
{
if (str[i] > str[pos])
{
pos = i;
}
}
i++;
}
char large = str[pos];
for(int i = pos; i > 0; i--)
str[i] = str[i-1];
str[0] = large;
}
I created a program. It works as I wanted it to work, but I don't understand why.
This is the function.
void LiteraMajuscula(char *str)
{
int i;
i = 0;
while (str[i] != '\0')
{
if (i == 0 && str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
if (str[i-1] == ' ' && str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
i++;
}
}
It is supposed to make the lowercase character into an uppercase one each time there is a space and only the first one and if the first character from a string is lowercase, make it an uppercase.
The only thing i dont understand is the str[i-1]. I tried str[i], but it doesn't change anything, and str[i-2] changes the second letter into and uppercase instead of the first one. Why is that?
str[i] -= 32; will convert the character at index i. The reason the second if statement uses str[i-1] == ' ' in its check is so it knows whether the current character (at i) is just after a space (at i - 1). The reason it converted the second character of words when you changed it to str[i-2] == ' ' is that you changed it so it converted a character if it (at i) was two characters after a space (at i-2).
As noted in the comments, the code there has undefined behavior, because there's nothing preventing the str[i-1] == ' ' check when i is 0, so str[i-1] would be accessing the character before where str is pointing.
Separately, since most of the conditions and logic are duplicated between the two ifs, this is where you'd use || (logical OR):
while (str[i] != '\0')
{
if ((i == 0 || str[i-1] == ' ') && str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
i++;
}
(Note the () around the ||.)
|| short-circuits, so when i is 0 and the first operand is true, the second operand (str[i-1] == ' ') is never evaluated and so you avoid undefined behavior.
The body of the loop is incorrect
while (str[i] != '\0')
{
if (i == 0 && str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
if (str[i-1] == ' ' && str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
i++;
}
When i is equal tp 0 then in this condition
if (str[i-1] == ' ' && str[i] >= 'a' && str[i] <= 'z')
^^^^^^^^
there is an attempt to access memory beyond the string. The loop should be rewritten at least like
while (str[i] != '\0')
{
if ( ( i == 0 || str[i-1] == ' ' ) && str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
i++;
}
That is the condition checks whether the first character of the string is an alpha character or if it is not the first character of the string whether the previous character is space and the current character is an alpha character.
Take into account that the function will not work with EBCDIC characters. It is better to use standard C function toupper declared in header <string.h>. For example
while (str[i] != '\0')
{
if ( i == 0 || str[i-1] == ' ' )
{
if (isalpha((unsigned char)s[i]) ) s[i] = toupper((unsigned char)s[i]);
}
i++;
}
I think it is desirable also to check whether the previous character is the tab character. Also such string functions usually return the target string.
I would write the function the following way
#include <stdio.h>
#include <ctype.h>
char * LiteraMajuscula( char *s )
{
for (size_t i = 0;
s[i += strspn(s + i, " \t")] != '\0';
i += strcspn( s + i, " \t" ))
{
if (isalpha((unsigned char)s[i]) ) s[i] = toupper((unsigned char)s[i]);
}
return s;
}
int main(void)
{
char s[] = "hello,\tworld!";
puts(s);
puts(LiteraMajuscula(s));
return 0;
}
Its output is
hello, world!
Hello, World!
The other answers posted have explained what was wrong with the code.
Here is an alternative way that the function can be rewritten to be more efficient and more portable, with the use of functions from ctype.h:
void do_some_incorrect_capitalization (char str[])
{
if(*str == '\0')
{
return ;
}
*str = toupper(*str); // special case, first letter in the string
str++;
while(*str != '\0')
{
if(isspace(*(str-1)))
{
*str = toupper(*str);
}
str++;
}
}
The string is a sentence and not just one word.
must be recursive.
here how I do it for one word. the first function change the first letter. the second function puts lower case in the rest.
Here what I tried:
void changeWord(char *str){
if (*str >= 'a' && *str <= 'z')
*str = *str - 32; //stop condition.
changeRest(str+1);
}
void changeRest(char *str){
if (*str !=0){ //STOP CONDITION.
if (*str >= 'A' && *str <= 'Z'){ //if its upper.
*str = *str +32; //change it to lower
}
changeRest(str+1); //call the new string -1.
}
return;
}
You need an additional argument to your recursive function to signal to it whether it is at the beginning of a sentence. It makes more sense then to combine your code into a single function rather than two. For example:
void capitalize(char *str, int sentence_start){
if (*str == '\0') { //STOP CONDITION.
return;
} else if (*str == '.') {
sentence_start = 1;
} else if (*str >= 'a' && *str <= 'z') {
if (sentence_start) {
*str = *str - 'a' + 'A';
sentence_start = 0;
}
} else if (*str >= 'A' && *str <= 'Z') {
if (sentence_start) {
sentence_start = 0;
} else {
*str = *str - 'A' + 'a';
}
}
capitalize(str + 1, sentence_start);
}
The top level call to that function would pass sentence_start nonzero if the first letter is to be capitalized; you could write a wrapper function to do that for you if you don't want to have to do it manually.
Of course, the above assumes that the uppercase and lowercase letters each appear in a contiguous block of character codes, of the same size and in corresponding order, with 'a' (respectively 'A') at the beginning and 'z' (respectively 'Z') at the end. That's rather U.S.-centric, but it seems to be what your requirements are aiming at.
The functions toupper and tolower in ctype.h are typically implemented like this:
char tolower (char ch)
{
if ((ch >= 'A') && (ch <= 'Z'))
{
ch = (ch - 'A') + 'a';
}
return ch;
}
char toupper (char ch)
{
if ((ch >= 'a') && (ch <= 'z'))
{
ch = (ch - 'a') + 'A';
}
return ch;
}
This addresses all your requirements.
Assumptions:
The supplied buffer contains a valid C-style string
The supplied pointer is non-null.
The presence of a period in the string strictly implies the end of a sentence.
From the above, no embedded floating point numbers. Thus "pi is about 3.14" is invalid (though this should handle it).
Character set is the native C one (ASCII, 7-bit)
Code, including helpers
// Keep all helpers as functions to avoid side effects of calls
// such as toupper(text++).
unsigned char toupper(unsigned char c)
{
return (c >= 'a' && c <= 'z') ? c - ('A' - 'a') ? c;
}
// All characters in the ranges [0,' '] and [0x7f,inf) are either
// whitespace, control characters, or otherwise non-printable.
int iswhitespace(unsigned char c)
{
return (c <= ' ' || c >= 0x7f)
}
int isalpha(unsigned char c)
{
unsigned char uc = toupper(c);
return uc >= 'A' && uc <= 'Z';
}
// Note that identifiers beginning with "str" are reserved
// by the standard library.
void Capitalize(unsigned char *text)
{
// Base condition: at the end of the string
if (! *text)
return;
// At the beginning of a sentence. Capitalize the first char.
*text = toupper(*text);
// Find the next sentence and recurse
for (text++; *text && *text != '.'; text++);
for (text++; *text && iswhitespace(*text); text++);
Capitalize(text);
}
An iterative function would work well here.
Here is a dual recursive solution.
#include <string.h>
int my_isalpha(char ch) {
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z');
}
char my_toupper(char ch) {
if (ch >= 'a' && ch <= 'z') {
ch = ch - 'a' + 'A';
}
return ch;
}
int EndOfSentence(int ch) {
return !!strchr(".?!\n\v\r", ch);
}
void Sentence_Case(char *src);
static void Normal_Case(char *src) {
while (*src) {
if (EndOfSentence(*src)) {
Sentence_Case(src + 1);
return;
}
src++;
}
}
void Sentence_Case(char *src) {
while (*src) {
if (my_isalpha(*src)) {
*src = my_toupper(*src);
Normal_Case(src + 1);
return;
}
src++;
}
}
#include <stdio.h>
int main(void) {
char s[] = "good job. sir";
Sentence_Case(s);
puts(s);
return 0;
}