我一直在审查一个程序,该程序将字符串中每个单词的首字母大写。例如,"every single day"
变成"Every Single Day"
。
我不了解str[i - 1] == ' '
部分。那是做什么的?
#include <stdio.h>
char *ft_strcapitalize(char *str)
{
int i;
i = 0;
while (str[i] != '\0')
{
if ((i == 0 || str[i - 1] == ' ') &&
(str[i] <= 'z' && str[i] >= 'a'))
{
str[i] -= 32;
}
else if (!(i == 0 || str[i - 1] == ' ') &&
(str[i] >= 'A' && str[i] <= 'Z'))
{
str[i] += 32;
}
i++;
}
return (str);
}
int main(void)
{
char str[] = "asdf qWeRtY ZXCV 100TIS";
printf("\n%s", ft_strcapitalize(str));
return (0);
}
答案 0 :(得分:1)
i
是您正在考虑将其大写的当前字符的字符串中的索引(记住它从0开始)。
i-1
是前一个字符的字符串到您正在考虑的字符的索引。
str[i-1]
是您要考虑的位置之前的位置的字符。
== ' '
正在将该字符与空格字符进行比较。
所以str[i-1] == ' '
的意思是“这个字符左边的字符是空格吗?”
答案 1 :(得分:1)
“
const diagMsg = { ...homu.message['await'].welCH.stat, color: toggle === true ? '#ffffff':'#2c2f33', msg: diagMsg.msg.replace('{{stat}}', 'Disabled'), foot: diagMsg.foot.replace( '{{prefix}}', homu.guildSettings.get(message.guild.id, 'prefix') ) };
是什么意思?”
str[i - 1] == ' '
是空白字符(ASCII值32)的字符常量。
' '
是调用者中指向str
的指针。 (实际上,它应该指向其中包含一个字符串的char
数组,而不仅仅是一个char
。)
char
是一个计数器。
请注意,C语法允许您将数组符号用于指针。因此,i
等于str[1]
。
*(str + 1)
中的[i - 1]
意味着您在元素str[i - 1]
指向之前访问该元素。
将str[i]
指向的元素与空白字符进行比较(如果元素str[i - 1]
指向的元素实际上包含空白)。
在这种情况下,条件的取值为str[i - 1]
,否则条件为true
。
注意事项:
请注意,false
可能很危险。然后,您将尝试访问指向数组之外的内存。但是对于您而言,这是安全的,因为由于逻辑或str[i - 1]
,只有i == 0
不是str[i - 1] == ' '
时才评估i == 0
。
true
因此在您的代码中会考虑这种情况。
||
等效于if ((i == 0 || str[i - 1] == ' ')
。当使用大写形式时,后一种形式可以提高可读性。
答案 2 :(得分:1)
它正在检查空格,或更确切地说是一行
if ((i == 0 || str[i - 1] == ' ')
检查我们是否正在查看字符串的开头或其前一行是否为空格,即检查是否遇到了新单词。
在字符串“ e 非常每天”中,i = 0
位于粗体位置,在第二种情况下为
“每天 s 天”,i = 6
和str[i-1]
' '
表示遇到了新单词
答案 3 :(得分:0)
在这里,您将str[i-1]
与字符space
(其ASCII码为32)进行比较。
例如
if(str[i-1] == ' ')
{
printf("Hello, I'm space.\n");
}
else
{
printf("You got here, into the false block.\n");
}
执行此代码段,如果比较结果为1,则为true,否则为false。放入str[] = "Ryan Mney";
,然后进行比较,您会了解发生了什么事?
答案 4 :(得分:0)
C语言提供了许多有用的字符宏,这些宏可用于使代码更可移植且更具可读性。尽管您正在查看的示例代码未使用这些宏,但请考虑使用这些宏使您的代码更可移植,更健壮并且更易于他人阅读。
请使用islower / isupper / isalpha和tolower / toupper宏;这些ctype宏使C语言字符串处理更易于阅读。
是的,它们是宏- What is the macro definition of isupper in C?
C语言提供了“ for”控制语句,该语句提供了一种表达字符串处理的好方法。简单的索引循环通常使用“ for”而不是“ 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);
}
轻微的重构使代码更具可读性,
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);
}
或者,使用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);
}
首先执行特殊情况(字符串的第一个字符),进一步简化条件表达式。
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);
}
再次,替代的isalpha(ch)版本,
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);
}
更惯用的是,只需使用一个“状态”标志来表明我们应该折叠为大写还是小写。
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);
}
还有您的主要测试驱动程序,
int main(void)
{
char str[] = "asdf qWeRtY ZXCV 100TIS";
printf("\n%s", ft_strcapitalize(str));
return (0);
}
答案 5 :(得分:0)
' '
是一个字符常量,表示执行集中空格字符的值。使用' '
而不是32
可以提高系统的可读性和可移植性,因为这些系统的空间值可能与ASCII字符集中的值不同。如果(i == 0 || str[i - 1] == ' ')
是空格分隔的单词列表中单词开头的偏移量,则i
为真。
尝试使其尽可能简单易读非常重要。如果更容易表达且更便宜的替代方法不建议使用32
之类的魔术常数。例如,您用str[i] -= 32
将小写字母转换为大写字母:此魔术值32
(再次!)恰好是小写字母和大写字母之间的偏移量。编写起来会更可读:
str[i] -= 'a' - 'A';
类似地,您以相反的顺序编写了针对小写和大写字母的范围测试:这容易出错,并使读者感到惊讶。
您还将重复测试单词开头:仅在单词开头测试小写字母,然后测试大写字母,否则会使代码更简单。
最后,在您的函数中,使用for
循环比while
循环更简洁,更不容易出错,但是我知道您学校的本地编码约定不允许for
循环(!)。
这是修改后的版本:
#include <stdio.h>
char *ft_strcapitalize(char *str) {
size_t i;
i = 0;
while (str[i] != '\0') {
if (i == 0 || str[i - 1] == ' ') {
if (str[i] >= 'a' && str[i] <= 'z') {
str[i] -= 'a' - 'A';
}
} else {
if (str[i] >= 'A' && str[i] <= 'Z') {
str[i] += 'a' - 'A';
}
}
i++;
}
return str;
}
int main(void) {
char str[] = "asdf qWeRtY ZXCV 100TIS";
printf("\n%s", ft_strcapitalize(str));
return 0;
}
请注意,以上代码仍假定字母以从a
到z
的相同顺序形成两个连续的块。这个假设适用于ASCII字符集,该字符集在当今几乎是通用的,但对于在某些大型机系统中仍然使用恒定偏移量但字母之间仍存在一定偏移量的EBCDIC字符集来说,只是部分原因而已。从a
到z
的区域不会形成连续的块。
更通用的方法是使用<ctype.h>
中的函数和宏来测试空白(空格和其他空白字符),字符大小写并转换大小写:
#include <ctype.h>
char *ft_strcapitalize(char *str) {
for (size_t i = 0; str[i] != '\0'; i++) {
if (i == 0 || isspace((unsigned char)str[i - 1]))
str[i] = toupper((unsigned char)str[i]);
else
str[i] = tolower((unsigned char)str[i]);
}
return str;
}