alg : 字符串单词反转


/// @file           SrcReverseWord.cpp
/// @brief          实现对串的单词逆序 e.g. Hello world driver => driver world Hello
///                 算法: 
///                 * 先对串进行整体逆序, 
///                 * 再找每个单词的分隔符' ', 确定每个单词内容
///                 * 对每个单词进行逆序

/// @note           测试环境: vs2008 + win7x64sp1

#include "stdafx.h"
#include <windows.h>
#include <locale.h>
#include <tchar.h>

#define WCHAR_STR_END   L'\0'   ///< 串结束符
#define WCHAR_WORD_END  L' '    ///< 单词结束符

#define SIZEOF_WCHAR_ARRAY(x)   (sizeof((x)) / sizeof(wchar_t))

/// @fn         ReverseStringByWord
/// @brief      对入参串进行单词反转, 单词之间的分隔符号为空格, 
///             e.g. Hello world, driver => driver world Hello
/// @param      IN OUT wchar_t * pcMsgW, 输入输出串, 反转后的结果串覆盖原字符串
/// @return     bool
/// @retval     true, 串反转成功
/// @retval     false, 串反转失败
bool    ReverseStringByWord(IN OUT wchar_t * pcMsgW);

/// @fn         ReverseString
/// @brief      对入参串进行完全反转
///             e.g. 123456 7890 => 0987 654321
/// @param      IN OUT wchar_t * pcMsgW, 输入输出串, 反转后的结果串覆盖原字符串
/// @param      IN size_t nLenMsg, 串长度
/// @return     bool
/// @retval     true, 串反转成功
/// @retval     false, 串反转失败
bool    ReverseString(IN OUT wchar_t * pcMsgW, IN size_t nLenMsg);

/// @fn         GetStringLength
/// @brief      此算法不允许用C库函数参与串长度计算, 模拟实现计算串长度
/// @param      IN const wchar_t * pcMsgW, 输入串
/// @param      IN const wchar_t & cEndSeparator, 串的结束分隔符
/// @param      IN const wchar_t & cStrEndSeparator, 字符串结尾字符
/// @return     size_t, 返回的串长度. 如果串为NULL, 返回0.
size_t  GetStringLength(IN const wchar_t * pcMsgW, 
                        IN const wchar_t & cEndSeparator, 
                        IN const wchar_t & cStrEndSeparator = WCHAR_STR_END);

int _tmain(int argc, _TCHAR* argv[])
{
    size_t      nLen    =   0;
    size_t      nPos    =   0;
    wchar_t     cInput  =   L' ';
    wchar_t     cBuf[_MAX_PATH];

    ::ZeroMemory(cBuf, sizeof(cBuf));
    setlocale(LC_CTYPE, ".936");    //< 控制台为中文输出

    _tprintf(L"请输入字符串, 支持中文和分隔符, 以回车作为输入结束符:\r\n");

    nLen = SIZEOF_WCHAR_ARRAY(cBuf);

    /// 测试用的字符串如下: 
    /// Hello world, Alg! 这是一个单词反转算法, 先进行字符串全反转, 再进行每个单词的反转.
    while(1)
    {
        cInput = getwchar();    ///< _tprintf_s 有问题,不支持','分隔, 采用getwchar循环接收代替
        if (L'\n' == cInput)
            break;

        if (nPos >= nLen)
            break;

        cBuf[nPos++] = cInput;
    }

    _tprintf(L"\r\n您输入的字符串为: [%s]\r\n", cBuf);

    if (ReverseStringByWord(cBuf))
        _tprintf(L"\r\n单词反转后的串为 : [%s]\n", cBuf);
    else
        _tprintf(L"\r\n输入串无效\r\n");

    _tprintf(L"\r\n运行完成, 按任意键退出\r\n");

    /** runresult
    请输入字符串, 支持中文和分隔符, 以回车作为输入结束符:
    Hello world, Alg! 这是一个单词反转算法, 先进行字符串全反转, 再进行每个单词的反转
    .

    您输入的字符串为: [Hello world, Alg! 这是一个单词反转算法, 先进行字符串全反转,
    再进行每个单词的反转.]

    单词反转后的串为 : [再进行每个单词的反转. 先进行字符串全反转, 这是一个单词反转算
    法, Alg! world, Hello]

    运行完成, 按任意键退出
    */
    getchar();

	return 0;
}

bool    ReverseStringByWord(wchar_t * pcMsgW)
{
    size_t  nLenAll     =   0;
    size_t  nPosNow     =   0;
    size_t  nPosPrev    =   0;
    size_t  nLenStr     =   0;

    if (NULL == pcMsgW)
        return false;

    /// 反转整个串
    nLenAll = GetStringLength(pcMsgW, WCHAR_STR_END);
    if (!ReverseString(pcMsgW, nLenAll))
        return false;

    /// 反转每个单词
    while (nPosPrev < (nLenAll - 1))
    {
        nLenStr = GetStringLength(pcMsgW + nPosPrev, WCHAR_WORD_END);

        /// 串长度 - 1 是位置, 位置是基于0的
        nPosNow = nPosPrev + nLenStr - 1;
        if ((nPosNow <= nPosPrev) 
            || (!ReverseString(pcMsgW + nPosPrev, nLenStr)))
            break;

        /// 下一个单词的起点是上一个单词的起点 + 一个单词分隔符长度 + 下一个单词的首字符
        nPosPrev = nPosNow + 2;
    }

    return true;
}

bool    ReverseString(IN OUT wchar_t * pcMsgW, IN size_t nLenMsg)
{
    wchar_t *   pcBegin =   NULL;
    wchar_t *   pcEnd   =   NULL;

    if (NULL == pcMsgW)
        return false;

    if (nLenMsg <= 1)
        return true;

    pcBegin = pcMsgW;
    pcEnd = pcMsgW + nLenMsg - 1;

    while (pcBegin < pcEnd)
    {
        /// 交换字符
        *pcBegin ^= *pcEnd;
        *pcEnd ^= *pcBegin;
        *pcBegin ^= *pcEnd;

        /// 移动头尾指针
        pcBegin++;
        pcEnd--;
    }

    return true;
}

size_t  GetStringLength(IN const wchar_t * pcMsgW, 
                        IN const wchar_t & cEndSeparator, 
                        IN const wchar_t & cStrEndSeparator)
{
    size_t          nLenCnt    =   0;
    const wchar_t * pcBegin =   pcMsgW;

    if (NULL == pcBegin)
        return 0;

    while ((*(pcBegin + nLenCnt) != cEndSeparator)
            && (*(pcBegin + nLenCnt) != cStrEndSeparator))
        nLenCnt++; ///< 当前字符不是cEndSeparator, 也不是字符串结尾, 计数++

    return nLenCnt;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值