【字符串處理算法】將輸入字符串中的各個(gè)單詞反序的算法設(shè)計(jì)及C代碼實(shí)現(xiàn)
一、需求描述
輸入一個(gè)字符串,編寫程序?qū)⒃撟址械母鱾€(gè)單詞反序拼裝并輸出。例如,如果輸入的字符串是“Hello, how do you do”,那么輸出的字符串為“do you do how Hello,”。注意保留各個(gè)單詞之間的空格及相應(yīng)的標(biāo)點(diǎn)符號(hào)。
二、算法設(shè)計(jì)
通過觀察示例字符串(即“Hello, how do you do”),我們可以看到該字符串中各個(gè)單詞與空格之間的關(guān)系為:單詞總數(shù)=空格總數(shù)+1。也就是說,示例字符串中的空格總數(shù)為4,單詞個(gè)數(shù)為5(即“Hello,”、“how”、“do”、“you”、“do”)。
因此,我們可以考慮先找出輸入字符串中的空格總數(shù),再根據(jù)空格找出各個(gè)單詞,然后將這些單詞反序拼裝起來。
程序的總體流程如圖1所示。
圖1 程序的總體流程
三、特殊流程考慮
在編寫程序的過程中,我們要對(duì)輸入字符串的格式多做考慮,如:
1.輸入字符串的開頭幾個(gè)字符為空格,即形如“ Hello,how do you do”,我們需要先將開頭的幾個(gè)空格去掉,再進(jìn)行后續(xù)處理。
2.輸入字符串的結(jié)尾幾個(gè)字符為空格,即形如“Hello, how do you do ”,我們需要先將結(jié)尾的幾個(gè)空格去掉,再進(jìn)行后續(xù)處理。
3.輸入字符串的中間幾個(gè)字符為連續(xù)的空格,即形如“Hello, how do youdo”,我們需要先將連續(xù)的空格合并為一個(gè)空格,再進(jìn)行后續(xù)處理。
4.只要輸入字符串中的兩個(gè)單詞之間出現(xiàn)了空格,我們都把它們當(dāng)作兩個(gè)不同的單詞,即使這兩個(gè)單詞沒有實(shí)際的意思,即形如“Hello, how do y ou do”,其中的“y”和“ou”雖然要合并在一起才有意義,但我們?nèi)匀话凑諆蓚€(gè)不同的單詞進(jìn)行處理。
四、程序代碼
- /**********************************************************************
- * 版權(quán)所有 (C)2016, Zhou Zhaoxiong。
- *
- * 文件名稱: ReverseTheString.c
- * 文件標(biāo)識(shí): 無
- * 內(nèi)容摘要: 將字符串中的單詞反序
- * 其它說明: 例如, 將"I'm a student"轉(zhuǎn)變?yōu)?quot;student a I'm"
- * 當(dāng)前版本: V1.0
- * 作 者: Zhou Zhaoxiong
- * 完成日期: 20160215
- *
- **********************************************************************/
- #include <stdio.h>
- #include <stdlib.h>
- // 重新定義數(shù)據(jù)類型
- typedef signed char INT8;
- typedef unsigned short int UINT16;
- typedef int INT32;
- typedef unsigned int UINT32;
- // 函數(shù)聲明
- INT32 GetFieldFromString(INT8 *pszIn, INT8 cSplitter, UINT16 iIdx, INT8 *pszOut, UINT16 iLen);
- void CombineSpace(INT8 *pszOldStr, INT8 *pszNewStr);
- /**********************************************************************
- * 功能描述: 主函數(shù)
- * 輸入?yún)?shù): 無
- * 輸出參數(shù): 無
- * 返 回 值: 0-執(zhí)行成功 其它-執(zhí)行失敗
- * 其它說明: 無
- * 修改日期 版本號(hào) 修改人 修改內(nèi)容
- * ---------------------------------------------------------------------
- * 20160215 V1.0 Zhou Zhaoxiong 創(chuàng)建
- ***********************************************************************/
- INT32 main()
- {
- INT8 szTestStr[500] = {0};
- INT8 szTmpStr[500] = {0}; // 用于存放經(jīng)過規(guī)范化處理之后的字符串
- INT8 szResultStr[500] = {0};
- INT8 szFieldVal[100] = {0};
- INT32 iPosFlag = 0;
- INT32 iRetFlag = 0;
- UINT32 iBlankCount = 0;
- printf("Please input the string: \n");
- gets(szTestStr);
- printf("TestStr=%s\n", szTestStr);
- // 去除測試字符串中多余的空格及前后的空格
- CombineSpace(szTestStr, szTmpStr);
- // 獲取測試字符串中的空格字符的個(gè)數(shù)
- iPosFlag = 0;
- while (szTmpStr[iPosFlag] != '\0')
- {
- if (szTmpStr[iPosFlag] == ' ')
- {
- iBlankCount ++;
- }
- iPosFlag ++;
- }
- // 將測試字符串中的單詞按照反序來拼接
- strcat(szTmpStr, " "); // 在測試字符串***面添加空格, 用于解析各個(gè)單詞
- for (iPosFlag = iBlankCount; iPosFlag >= 0; iPosFlag --)
- {
- memset(szFieldVal, 0x00, sizeof(szFieldVal));
- iRetFlag = GetFieldFromString(szTmpStr, ' ', iPosFlag, szFieldVal, sizeof(szFieldVal)-1);
- if (iRetFlag != 0)
- {
- printf("Exec GetFieldFromString to get FieldVal failed!\n");
- return -1;
- }
- if (strlen(szResultStr) > sizeof(szResultStr)-1) // 字符串超長, 直接退出
- {
- break;
- }
- else
- {
- strcat(szResultStr, szFieldVal); // 將各個(gè)單詞拼接起來
- strcat(szResultStr, " "); // 在各個(gè)單詞后面添加空格
- }
- }
- if (szResultStr[strlen(szResultStr)-1] == ' ')
- {
- szResultStr[strlen(szResultStr)-1] = '\0'; // 去除***面的空格
- }
- printf("ResultStr=%s\n", szResultStr);
- return 0;
- }
- /**********************************************************************
- * 功能描述: 從字符串中獲取字段的值
- * 輸入?yún)?shù): 無
- * 輸出參數(shù): 無
- * 返 回 值: 0-執(zhí)行成功 其它-執(zhí)行失敗
- * 其它說明: 無
- * 修改日期 版本號(hào) 修改人 修改內(nèi)容
- * ---------------------------------------------------------------------
- * 20160215 V1.0 Zhou Zhaoxiong 創(chuàng)建
- ***********************************************************************/
- INT32 GetFieldFromString(INT8 *pszIn, INT8 cSplitter, UINT16 iIdx, INT8 *pszOut, UINT16 iLen)
- {
- INT8 *pszStart = NULL;
- INT8 *pszEnd = NULL;
- UINT16 iCount = 0;
- UINT16 iFiledLen = 0;
- INT8 szBuf[1024] = {0};
- if (NULL == pszIn || NULL == pszOut)
- {
- return -1;
- }
- pszStart = pszIn;
- for (iCount = 0; iIdx != iCount; iCount++) // for循環(huán)用于查找當(dāng)前字段的起始位置
- {
- pszStart = strchr(pszStart, cSplitter);
- if (NULL == pszStart)
- {
- break;
- }
- else
- {
- pszStart ++;
- }
- }
- if (NULL == pszStart)
- {
- return -2;
- }
- pszEnd = strchr(pszStart, cSplitter);
- if (NULL == pszEnd)
- {
- return -3;
- }
- // 判斷長度大小, 防止拷貝字符串時(shí)越界
- if (pszEnd - pszStart > sizeof(szBuf)-1)
- {
- iFiledLen = sizeof(szBuf)-1;
- }
- else
- {
- iFiledLen = pszEnd - pszStart;
- }
- strncpy(szBuf, pszStart, iFiledLen);
- if (iLen < iFiledLen) // 傳入的長度太小
- {
- return -4;
- }
- strncpy(pszOut, szBuf, iFiledLen);
- return 0;
- }
- /**********************************************************************
- * 功能描述:合并多個(gè)連續(xù)空格為一個(gè), 并去掉首位的空格
- * 輸入?yún)?shù):pszOldStr-合并空格之前的字符串
- * 輸出參數(shù):pszNewStr-合并空格之后的字符串
- * 返 回 值:無
- * 其它說明:無
- * 修改日期 版本號(hào) 修改人 修改內(nèi)容
- * -------------------------------------------------------------------
- * 20160215 V1.0 Zhou Zhaoxiong 創(chuàng)建
- ***********************************************************************/
- void CombineSpace(INT8 *pszOldStr, INT8 *pszNewStr)
- {
- UINT32 iOldIndex = 0;
- UINT32 iNewIndex = 0;
- INT8 chSingleChar = '\0';
- INT8 iIsSpace = 0;
- INT8 szTmpNewStr[100] = {0};
- if ((NULL == pszOldStr) || (NULL == pszNewStr))
- {
- return;
- }
- while ('\0' != (chSingleChar = pszOldStr[iOldIndex++]))
- {
- if (chSingleChar == ' ') // 多個(gè)連續(xù)空格只保留一個(gè)
- {
- if (iIsSpace == 0)
- {
- iIsSpace = 1;
- szTmpNewStr[iNewIndex++] = chSingleChar;
- }
- }
- else
- {
- iIsSpace = 0;
- szTmpNewStr[iNewIndex++] = chSingleChar;
- }
- }
- // 如果***一個(gè)字符是空格, 則將其去掉
- if (szTmpNewStr[strlen(szTmpNewStr)-1] == ' ')
- {
- szTmpNewStr[strlen(szTmpNewStr)-1] = '\0';
- }
- // 如果***個(gè)字符是空格, 則將其去掉
- if (szTmpNewStr[0] == ' ')
- {
- memcpy(pszNewStr, szTmpNewStr+1, strlen(szTmpNewStr)-1);
- }
- else
- {
- memcpy(pszNewStr, szTmpNewStr, strlen(szTmpNewStr));
- }
- return;
- }
五、程序測試
我們將編寫好的程序“ReverseTheString.c”上傳到Linux機(jī)器,并使用“gcc -g -o ReverseTheStringReverseTheString.c”命令對(duì)該程序進(jìn)行編譯,生成“ReverseTheString”文件。下面對(duì)程序進(jìn)行詳細(xì)的測試。
1.輸入字符串為“Hello, how do you do”時(shí),程序運(yùn)行情況如下:
- Please input the string:
- Hello, how do you do
- TestStr=Hello, how do you do
- ResultStr=do you do how Hello,
2.輸入字符串為“ Hello, how do you do”(注意,前面有兩個(gè)空格)時(shí),程序運(yùn)行情況如下:
- Please input the string:
- Hello, how do you do
- TestStr= Hello, how doyou do
- ResultStr=do you do how Hello,
3.輸入字符串為“Hello, how do you do ”(注意,后面有兩個(gè)空格)時(shí),程序運(yùn)行情況如下:
- Please input the string:
- Hello, how do you do
- TestStr=Hello, how do you do
- ResultStr=do you do how Hello,
4.輸入字符串為“Hello, how do you do”(注意,中間有連續(xù)的空格)時(shí),程序運(yùn)行情況如下:
- Please input the string:
- Hello, how do you do
- TestStr=Hello, howdo you do
- ResultStr=do you do how Hello,
5.輸入字符串為“Hello, ho w do yo u do”(注意,將幾個(gè)完整的單詞用空格分開)時(shí),程序運(yùn)行情況如下:
- Please input the string:
- Hello, ho w do yo u do
- TestStr=Hello, ho w do yo u do
- ResultStr=do u yo do w ho Hello,
可見,對(duì)于上面考慮到的幾種特殊情況,程序均能做出正確的處理。
六、需求擴(kuò)展
基于本文中的需求和程序,我們可考慮對(duì)需求進(jìn)行以下擴(kuò)展:
1.將反序之后的字符串的首字母大小,并將反序之前的首字母從大寫變?yōu)樾?,即?ldquo;Hello, how do you do”轉(zhuǎn)換為“Do you do how hello,”。
2.不改變?cè)址械?**的標(biāo)點(diǎn)符號(hào)的位置,即將“Hello, how do you do!”轉(zhuǎn)換為“do you do how Hello,!”。
3.將原字符串中的標(biāo)點(diǎn)符號(hào)去掉,即將“Hello, how do you do!”轉(zhuǎn)換為“do you do how Hello”。
【本文是51CTO專欄作者周兆熊的原創(chuàng)文章,作者微信公眾號(hào):周氏邏輯(logiczhou)】