一、需求描述
输入一个字符串,编写程序将该字符串中的各个单词反序拼装并输出。例如,如果输入的字符串是“Hello, how do you do”,那么输出的字符串为“do you do how Hello,”。注意保留各个单词之间的空格及相应的标点符号。
二、算法设计
通过观察示例字符串(即“Hello, how do you do”),我们可以看到该字符串中各个单词与空格之间的关系为:单词总数=空格总数+1。也就是说,示例字符串中的空格总数为4,单词个数为5(即“Hello,”、“how”、“do”、“you”、“do”)。
因此,我们可以考虑先找出输入字符串中的空格总数,再根据空格找出各个单词,然后将这些单词反序拼装起来。
程序的总体流程如图1所示。
图1 程序的总体流程
三、特殊流程考虑
在编写程序的过程中,我们要对输入字符串的格式多做考虑,如:
1.输入字符串的开头几个字符为空格,即形如“ Hello,how do you do”,我们需要先将开头的几个空格去掉,再进行后续处理。
2.输入字符串的结尾几个字符为空格,即形如“Hello, how do you do ”,我们需要先将结尾的几个空格去掉,再进行后续处理。
3.输入字符串的中间几个字符为连续的空格,即形如“Hello, how do youdo”,我们需要先将连续的空格合并为一个空格,再进行后续处理。
4.只要输入字符串中的两个单词之间出现了空格,我们都把它们当作两个不同的单词,即使这两个单词没有实际的意思,即形如“Hello, how do y ou do”,其中的“y”和“ou”虽然要合并在一起才有意义,但我们仍然按照两个不同的单词进行处理。
四、程序代码
- /**********************************************************************
- * 版权所有 (C)2016, Zhou Zhaoxiong。
- *
- * 文件名称: ReverseTheString.c
- * 文件标识: 无
- * 内容摘要: 将字符串中的单词反序
- * 其它说明: 例如, 将"I'm a student"转变为"student a I'm"
- * 当前版本: V1.0
- * 作 者: Zhou Zhaoxiong
- * 完成日期: 20160215
- *
- **********************************************************************/
- #include <stdio.h>
- #include <stdlib.h>
- // 重新定义数据类型
- typedef signed char INT8;
- typedef unsigned short int UINT16;
- typedef int INT32;
- typedef unsigned int UINT32;
- // 函数声明
- INT32 GetFieldFromString(INT8 *pszIn, INT8 cSplitter, UINT16 iIdx, INT8 *pszOut, UINT16 iLen);
- void CombineSpace(INT8 *pszOldStr, INT8 *pszNewStr);
- /**********************************************************************
- * 功能描述: 主函数
- * 输入参数: 无
- * 输出参数: 无
- * 返 回 值: 0-执行成功 其它-执行失败
- * 其它说明: 无
- * 修改日期 版本号 修改人 修改内容
- * ---------------------------------------------------------------------
- * 20160215 V1.0 Zhou Zhaoxiong 创建
- ***********************************************************************/
- INT32 main()
- {
- INT8 szTestStr[500] = {0};
- INT8 szTmpStr[500] = {0}; // 用于存放经过规范化处理之后的字符串
- 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);
- // 获取测试字符串中的空格字符的个数
- iPosFlag = 0;
- while (szTmpStr[iPosFlag] != '\0')
- {
- if (szTmpStr[iPosFlag] == ' ')
- {
- iBlankCount ++;
- }
- iPosFlag ++;
- }
- // 将测试字符串中的单词按照反序来拼接
- strcat(szTmpStr, " "); // 在测试字符串***面添加空格, 用于解析各个单词
- 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); // 将各个单词拼接起来
- strcat(szResultStr, " "); // 在各个单词后面添加空格
- }
- }
- if (szResultStr[strlen(szResultStr)-1] == ' ')
- {
- szResultStr[strlen(szResultStr)-1] = '\0'; // 去除***面的空格
- }
- printf("ResultStr=%s\n", szResultStr);
- return 0;
- }
- /**********************************************************************
- * 功能描述: 从字符串中获取字段的值
- * 输入参数: 无
- * 输出参数: 无
- * 返 回 值: 0-执行成功 其它-执行失败
- * 其它说明: 无
- * 修改日期 版本号 修改人 修改内容
- * ---------------------------------------------------------------------
- * 20160215 V1.0 Zhou Zhaoxiong 创建
- ***********************************************************************/
- 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循环用于查找当前字段的起始位置
- {
- pszStart = strchr(pszStart, cSplitter);
- if (NULL == pszStart)
- {
- break;
- }
- else
- {
- pszStart ++;
- }
- }
- if (NULL == pszStart)
- {
- return -2;
- }
- pszEnd = strchr(pszStart, cSplitter);
- if (NULL == pszEnd)
- {
- return -3;
- }
- // 判断长度大小, 防止拷贝字符串时越界
- 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;
- }
- /**********************************************************************
- * 功能描述:合并多个连续空格为一个, 并去掉首位的空格
- * 输入参数:pszOldStr-合并空格之前的字符串
- * 输出参数:pszNewStr-合并空格之后的字符串
- * 返 回 值:无
- * 其它说明:无
- * 修改日期 版本号 修改人 修改内容
- * -------------------------------------------------------------------
- * 20160215 V1.0 Zhou Zhaoxiong 创建
- ***********************************************************************/
- 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 == ' ') // 多个连续空格只保留一个
- {
- if (iIsSpace == 0)
- {
- iIsSpace = 1;
- szTmpNewStr[iNewIndex++] = chSingleChar;
- }
- }
- else
- {
- iIsSpace = 0;
- szTmpNewStr[iNewIndex++] = chSingleChar;
- }
- }
- // 如果***一个字符是空格, 则将其去掉
- if (szTmpNewStr[strlen(szTmpNewStr)-1] == ' ')
- {
- szTmpNewStr[strlen(szTmpNewStr)-1] = '\0';
- }
- // 如果***个字符是空格, 则将其去掉
- if (szTmpNewStr[0] == ' ')
- {
- memcpy(pszNewStr, szTmpNewStr+1, strlen(szTmpNewStr)-1);
- }
- else
- {
- memcpy(pszNewStr, szTmpNewStr, strlen(szTmpNewStr));
- }
- return;
- }
五、程序测试
我们将编写好的程序“ReverseTheString.c”上传到Linux机器,并使用“gcc -g -o ReverseTheStringReverseTheString.c”命令对该程序进行编译,生成“ReverseTheString”文件。下面对程序进行详细的测试。
1.输入字符串为“Hello, how do you do”时,程序运行情况如下:
- 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”(注意,前面有两个空格)时,程序运行情况如下:
- 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 ”(注意,后面有两个空格)时,程序运行情况如下:
- 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”(注意,中间有连续的空格)时,程序运行情况如下:
- 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”(注意,将几个完整的单词用空格分开)时,程序运行情况如下:
- 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,
可见,对于上面考虑到的几种特殊情况,程序均能做出正确的处理。
六、需求扩展
基于本文中的需求和程序,我们可考虑对需求进行以下扩展:
1.将反序之后的字符串的首字母大小,并将反序之前的首字母从大写变为小写,即将“Hello, how do you do”转换为“Do you do how hello,”。
2.不改变原字符串中的***的标点符号的位置,即将“Hello, how do you do!”转换为“do you do how Hello,!”。
3.将原字符串中的标点符号去掉,即将“Hello, how do you do!”转换为“do you do how Hello”。
【本文是51CTO专栏作者周兆熊的原创文章,作者微信公众号:周氏逻辑(logiczhou)】