1. 程式人生 > >刪除空格:刪除字串首部和尾部連續的空格

刪除空格:刪除字串首部和尾部連續的空格


【筆試題目】
給定一個字串,實現如下函式介面,刪除其首部和尾部連續的空格。(注:夾在非空格字元之間的空格是合法的,不用刪除。)

    char* delete_leading_trailing_whitespaces(char *output,  const char *input);

【測試樣例】

編號 情況 輸入 輸出
1 空字串 “” NULL
2 空格字串 " " NULL
3 首尾無空格 “Hello World” “Hello World”
4 首部有空格 " Hello World" “Hello World”
5 尾部有空格 "Hello World " “Hello World”
6 首尾無空格 " Hello World " “Hello World”

【方法一】狀態標記法

【基本思路】找到output的頭(start)和尾(end)在input中的指標位置,然後把start到end的所有字元拷貝到output中。
此外,在遍歷處理input的過程中,維護一個狀態變數state,用於標記當前處理狀態是否處於空格字串狀態,其定義如下:

	enum {
		STATE_OUT, /* 值為0,表示當前狀態處於非空格字串狀態 */
		STATE_IN, /* 值為1,表示當前狀態處於空格字串狀態 */
	} state;

1、找出output的頭

我們知道,通過下面這個迴圈,可以跳過字串首部的空格。當跳出迴圈時,指標指向input的第一個非空格字元。

	while
(*input == ' ') { input++; }

如果該非空格字元是尾零’\0’,那麼表明input是空格字串,此時output應該返回NULL;

	if (*input == '\0)
	{
		output = NULL;
		return output;
	}

否則,該非空格字元就是output的首個字元。此時,設定狀態變數state為STATE_OUT狀態,表示當前指標處於非空格狀態,並且記錄下當前指標位置start。

2、迴圈處理剩餘的部分。

當指標指向空格字元時,標記當前狀態為STATE_IN狀態,表示當前指標處於連續的空格狀態;
當指標指向非空格狀態時,狀態變更為STAT_OUT狀態,表示當前指標處於非連續的空格狀態。
{
	//TODO:新增相關圖片解釋
}
此外,狀態每次由STATE_OUT轉為STATE_IN時,都需要記錄當時STATE_IN狀態的指標位置end,表示從該位置開始後面可能一直是空格;
而狀態每次由STATE_IN轉為STATE_OUT狀態時,需把end指標重置為NULL,表示之前的連續空格串不是input尾部的。

4、尾部空格串的判斷

隨著指標位置逐步地偏移,最終到達尾零'\0'。那麼怎麼判斷input尾部是否存在連續的空格呢?
如果此時state為STATE_IN,那就是存在的。而記錄下的end指標就是output的結尾,將其賦值為'\0'就可以得出output。

5、求出output

copy區間[start,end)的字元到output中。

【測試樣例4和6過程分析】

案例4和案例6分析


【方法二】

【基本思路】首先,從input的頭部迴圈偏移到第一個非空格字元,找到output的start位置;同理,從input的尾部迴圈偏移到第一個非空格字元,找到output的end位置;最後,copy區間[start,end]的字元到output中。


【實現程式碼】

【方法一】

char* delete_leading_trailing_whitespaces(char *output,  const chat*input)
{
	// 定義狀態變數state
	enum {
		STATE_OUT,
		STATE_IN,
	} state = STATE_OUT;

	// 定義output的start和end指標
	char *start = NULL, *end = NULL;

	// 傳入引數input和output檢查
	if (!input || !output)
		return NULL;

	// 跳過input首部的連續空格
	while (*input == ' ')
		input++;

	// input為空格字串
	if (*input == '\0')
		return NULL;

	// 記錄start
	start = const_cast<char*>(input++);

	// 處理input剩餘的部分
	while (*input != '\0')
	{
		if ((*input == ' '))
		{
			if (state == STATE_OUT)
			{
				state = STATE_IN;
				end = const_cast<char*>(input);
			}
		}
		else
		{
			end = NULL;
			state = STATE_OUT;
		}

		input++;
	}

	if (state == STATE_IN)
	{
		printf("has trailing spaces\n");
	}
	else
	{
		end = const_cast<char*>(input);
	}
	
	// copy從start到end的字元
	for (start; start < end; start++)
	{
		*output = *start;
		output++;
	}
	*output++ = '\0';
	
	return output;
}

【方法二】

char* delete_leading_trailing_whitespaces(char *output,  const chat*input)
{
	// 定義output的start和end指標
	char *start = input, *end = input;

	// 傳入引數input和output檢查
	if (!input || !output)
		return NULL;

	// 跳過input首部的連續空格
	while (*input == ' ')
		input++;

	// input為空格字串
	if (*input == '\0')
		return NULL;

	// 記錄start
	start = input;

	// 反向處理找end
	while (*end != '\0')
		end++;
	end--;
	while (*end == ' ')
		end--;
	
	// copy從start到end的字元
	for (start; start <= end; start++)
	{
		*output = *start;
		output++;
	}
	*output++ = '\0';
	
	return output;
}


【測試程式碼】

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{
	if (argc != 2)
	{
		fpritnf(stderr, "Usage: %s string\n", argv[0]);
		return 1;
	}

	char *output = (char*)malloc(32);
	delete_leading_trailing_whitespaces(output, argv[1]);
	printf("output = [%s]", output);
	
	return 0;
}