處理一個字符串,刪除其中多餘的空格、水平制表符(\t)和空行,並滿足以下條件:
使用有限狀態機(FSM)的思想,在單次遍歷中完成原地修改。維護一個狀態變量 state 記錄前一個有效字符的類型(普通字符、空格/制表符、換行符),並用雙指針 i(讀指針)和 j(寫指針)同步移動。
state = 0:初始狀態,或剛寫入普通字符state = 1:剛寫入一個空格(代表空格/制表符合併)state = 2:剛寫入一個換行符(代表空行合併)void remove_extra_space(char *str) {
int state = 0;
int i = 0, j = 0;
while (str[i] != '\0') {
if (str[i] == ' ' || str[i] == '\t') { // 遇到空格或制表符
if (state == 0 || state == 1) { // 前面是普通字符或已有空格
if (state == 0) str[j++] = ' '; // 首次遇到,寫入一個空格
state = 1; // 標記已寫入空格
}
// state == 2 時:前面是換行符,根據規則5,空行優先,忽略空格
} else if (str[i] == '\n') { // 遇到換行符
if (state == 0 || state == 1 || state == 2) {
if (state != 2) str[j++] = '\n'; // 寫入換行符(避免重複)
state = 2;
}
} else { // 普通可見字符
if (state == 1) { // 前面有空格,需決定保留空格還是換行
// 這裡簡化處理:若前面有空格且當前非換行,保留空格
str[j++] = str[i];
} else if (state == 2) { // 前面是換行符
str[j++] = str[i];
} else { // 普通字符連續
str[j++] = str[i];
}
state = 0;
}
i++;
}
// 處理結尾:若以空格或換行結束,回退刪除
if (state == 1 || state == 2) j--;
str[j] = '\0';
}
參考 playerc 的實現,使用指針運算更簡潔高效:
void remove_extra_space(char *str) {
char *sp = str, *prev = str;
// 跳過開頭空白
while (*str && (*str == ' ' || *str == '\t' || *str == '\n')) ++str;
while (*str) {
if (*str == ' ' || *str == '\t') {
if (*prev != ' ' && *prev != '\t' && *prev != '\n') {
*prev = *sp++ = ' ';
}
} else if (*str == '\n') {
if (*prev != ' ' && *prev != '\t' && *prev != '\n') {
*prev = *sp++ = '\n';
}
} else {
*prev = *sp++ = *str;
}
prev = str++;
}
// 處理結尾空白
if (prev && *prev && (*prev == ' ' || *prev == '\t' || *prev == '\n')) --sp;
*sp = '\0';
}
playerc 原文:C語言刪除字符串多餘空格
感謝所有提供寶貴意見的朋友!