[英]What does str[i - 1] == ' ' mean?
我一直在審查一個將字符串中每個單詞的首字母大寫的程序。 例如, "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);
}
i
是您正在考慮大寫的當前字符的字符串中的索引(記住它從 0 開始)。
i-1
是您正在考慮的前一個字符的字符串中的索引。
str[i-1]
是您正在考慮的字符之前的 position 中的字符。
== ' '
將該字符與空格字符進行比較。
所以str[i-1] == ' '
意思是“這個左邊的字符是空格嗎?”
“
str[i - 1] == ' '
是什么意思? ”
' '
是空白字符的字符常量(ASCII 值 32)。
str
是調用者中指向char
的指針。 (實際上,它應該指向一個char
數組,其中包含一個字符串,而不僅僅是一個char
)。
i
是櫃台。
請注意,C 語法允許您對指針使用數組表示法。 因此, str[1]
等於*(str + 1)
。
str[i - 1]
[i - 1]
中的 [i - 1] 表示您在元素str[i]
指向之前訪問該元素。
指向的元素str[i - 1]
與空白字符進行比較(如果指向的元素str[i - 1]
實際上包含空白)。
如果是這種情況,則條件評估為true
,否則條件為false
。
旁注:
請注意,當i == 0
時, str[i - 1]
可能很危險。 然后,您將嘗試在指向數組的范圍之外訪問 memory。 但是在您的情況下,這是安全的,因為str[i - 1] == ' '
僅在i == 0
不是true
時才被評估,這要歸功於邏輯 OR ||
.
if ((i == 0 || str[i - 1] == ' ')
因此,您的代碼中考慮了這種情況。
str[i] -= 32;
相當於str[i] -= 'a' - 'A';
. 后一種形式可以提高可讀性,因為大寫性質成為焦點。
它正在檢查空格,或者更准確地說,檢查行
if ((i == 0 || str[i - 1] == ' ')
檢查我們是否正在查看字符串開頭或其前一行是否為空格,即檢查是否遇到了新單詞。 在字符串“ e very single day”中, i = 0
在粗體 position 處,在下一種情況下,
"every s ingle day", i = 6
and str[i-1]
is ' '
標記遇到一個新詞
在這里,您將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,則為真,否則為假。 把str[] = "Ryan Mney";
再對比一下你就明白了,這是怎么回事?
C 語言提供了許多有用的字符宏,它們可用於使代碼更便攜、更易讀。 盡管您正在查看的示例代碼不使用這些宏,但請考慮使用這些宏來使您的代碼更便攜、更健壯並且更易於其他人閱讀。
請使用 islower/isupper/isalpha 和 tolower/toupper 宏; 這些 ctype 宏使 C 語言字符串處理更易於閱讀。
是的,它們是宏 - C 中 isupper 的宏定義是什么?
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);
}
' '
是一個字符常量,表示執行集中空格字符的值。 使用' '
而不是32
可以提高系統的可讀性和可移植性,因為系統中空格的值可能與 ASCII 字符集中的值不同。 (i == 0 || str[i - 1] == ' ')
如果i
是空格分隔的單詞列表中單詞開頭的偏移量,則為真。
重要的是要盡可能簡單易讀。 當更具表現力的替代方案既簡單又便宜時,不建議使用像32
這樣的魔法常數。 例如,您使用str[i] -= 32
將小寫字符轉換為大寫:這個神奇的值32
(再次。)恰好是小寫字符和大寫字符之間的偏移量:這樣寫起來更易讀:
str[i] -= 'a' - 'A';
類似地,您以相反的順序編寫了小寫和大寫的范圍測試:這容易出錯並且令讀者驚訝。
您還重復了單詞開頭的測試:僅在單詞開頭測試小寫字母並測試大寫字母,否則會使代碼更簡單。
最后,使用for
循環比 function 中的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
的字母不形成 a連續塊。
更通用的方法是使用<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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.