The C-language provides a number of useful character macros that can be used to both make code more portable, and more readable. Although the sample code you are reviewing does not use these macros, please consider using these macros to make your code more portable, more robust, and easier for others to read.
Please use the islower/isupper/isalpha and tolower/toupper macros; these ctype macros make C-language string processing easier to read.
- islower(ch) - check whether ch is lower case
- isupper(ch) - check whether ch is upper case
- isalpha(ch) - check whether ch is alphabetic (lower or upper case)
- tolower(ch) - convert ch to lower case (if it is alphabetic)
- toupper(ch) - convert ch to upper case (if it is alphabetic)
Yes, they are macros -
What is the macro definition of isupper in C?
The C-language provides the 'for' control statement which provides a nice way to express string processing. Simple indexed loops are often written using 'for' rather than 'while'.
#include <ctype.h>
char*
ft_strcapitalize(char *str)
{
for( int i=0; (str[i] != '\0'); i++ )
{
if ((i == 0 || isspace(str[i - 1])) && islower(str[i]) )
{
str[i] = toupper(str[i]);
}
else if (!(i == 0 || str[i - 1] == ' ') && isupper(str[i]) )
{
str[i] = tolower(str[i]);
}
}
return (str);
}
A slight refactoring makes the code a bit more readable,
char*
ft_strcapitalize(char *str)
{
for( int i=0; (str[i] != '\0'); i++ )
{
if( (i == 0 || isspace(str[i - 1])) )
{
if( islower(str[i]) ) str[i] = toupper(str[i]);
}
else if( !(i == 0 || isspace(str[i - 1]) )
{
if( isupper(str[i]) ) str[i] = tolower(str[i]);
}
}
return(str);
}
Alternately, use isalpha(ch),
char*
ft_strcapitalize(char *str)
{
for( int i=0; (str[i] != '\0'); i++ )
{
if( (i == 0 || isspace(str[i - 1])) )
{
if( isalpha(str[i]) ) str[i] = toupper(str[i]);
}
else if( !(i == 0 || isspace(str[i - 1]) )
{
if( isalpha(str[i]) ) str[i] = tolower(str[i]);
}
}
return(str);
}
Simplify the conditional expression even further, by performing the special case (first character of string) first.
char*
ft_strcapitalize(char *str)
{
if( islower(str[0]) ) str[0] = toupper(str[0]);
for( int i=1; (str[i] != '\0'); i++ )
{
if( isspace(str[i - 1]) )
{
if( islower(str[i]) ) str[i] = toupper(str[i]);
}
else if( !isspace(str[i - 1]) )
{
if( isupper(str[i]) ) str[i] = tolower(str[i]);
}
}
return(str);
}
Again, the alternate isalpha(ch) version,
char*
ft_strcapitalize(char *str)
{
if( isalpha(str[0]) ) str[0] = toupper(str[0]);
for( int i=1; (str[i] != '\0'); i++ )
{
if( isspace(str[i - 1]) )
{
if( isalpha(str[i]) ) str[i] = toupper(str[i]);
}
else if( !isspace(str[i - 1]) )
{
if( isalpha(str[i]) ) str[i] = tolower(str[i]);
}
}
return(str);
}
Even more idiomatic, just use a 'state' flag that indicates whether we should fold to upper or lower case.
char*
ft_strcapitalize(char *str)
{
int first=1;
for( char* p=str; *p; p++ ) {
if( isspace(*p) ) {
first = 1;
}
else if( !isspace(*p) ) {
if( first ) {
if( isalpha(str[i]) ) str[i] = toupper(str[i]);
first = 0;
}
else {
if( isalpha(str[i]) ) str[i] = tolower(str[i]);
}
}
}
return(str);
}
And your main test driver,
int main(void)
{
char str[] = "asdf qWeRtY ZXCV 100TIS";
printf("\n%s", ft_strcapitalize(str));
return (0);
}