基于Windows Sdk 与visual C++2008 在微软平台上构架自己的语音朗读引擎(适用于windows 2

本文介绍了一款在微软平台上运行的开源语音朗读引擎,该系统由个人开发者创建,旨在提供强大的语音朗读功能。文章详细展示了引擎的核心源码结构,包括编译后的体积大小、适用的操作系统以及关键的代码实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

               

本人闲来无事,自行开发了一个小型的语音朗读引擎,搭建起在微软平台上的语音朗读框架服务体系,

鉴于本人个人力量有限,为了将语音朗读引擎做的功能更加强悍,强大,

现在将该系统开源,需要源码的请在本人优快云博客下留下EMail,

本系统属于系统框架,搭建起一个语音朗读的引擎服务框架,

在微软平台上畅通无阻,

 

现在将本系统构架公布一下,

并贴出相关核心源码,源码体积为27M,编译后为1M,

适用于windows 2000/xp2003/vista   windows CE /mobile

 

 

#include "stdafx.h"#include <SampleTtsEngine_i.c>#include <direct.h>int wmain(int argc, __in_ecount(argc) WCHAR* argv[]){    static const DWORD dwVersion = { 1 };    ULONG ulNumWords = 0;    HRESULT hr = S_OK;    if( argc != 4 )    {        printf( "%s", "Usage: > MakeVoice [[in]word list file] [[out]voice file] [voice name]/n" );        hr = E_INVALIDARG;    }    else    {        ::CoInitialize( NULL );        FILE *hWordList = NULL, *hVoiceFile = NULL;        if ( fopen_s( &hWordList, CW2A(argv[1]), "r" ) != 0 )        {            hWordList = NULL;            hr = E_FAIL;        }                if ( SUCCEEDED( hr ) && fopen_s( &hVoiceFile, CW2A(argv[2]), "wb" ) != 0 )        {            hVoiceFile = NULL;            hr = E_FAIL;        }        if( SUCCEEDED( hr ) )        {            if( !fwrite( &dwVersion, sizeof(dwVersion), 1, hVoiceFile ) ||                 fseek( hVoiceFile, 4, SEEK_CUR ) )            {                hr = E_FAIL;            }            WCHAR WordFileName[MAX_PATH];            while( SUCCEEDED( hr ) && fgetws( WordFileName, MAX_PATH, hWordList ) )            {                ULONG ulTextLen = (ULONG)wcslen( WordFileName );                if( WordFileName[ulTextLen-1] == '/n' )                {                    WordFileName[--ulTextLen] = NULL;                }                ulTextLen = (ulTextLen+1) * sizeof(WCHAR);                if( fwrite( &ulTextLen, sizeof(ulTextLen), 1, hVoiceFile ) &&                    fwrite( WordFileName, ulTextLen, 1, hVoiceFile ) )                {                    ++ulNumWords;                             ISpStream* pStream;                    wcscat_s( WordFileName, _countof(WordFileName), L".wav" );                    hr = SPBindToFile( WordFileName, SPFM_OPEN_READONLY, &pStream );                    if( SUCCEEDED( hr ) )                    {                        CSpStreamFormat Fmt;                        Fmt.AssignFormat(pStream);                        if( Fmt.ComputeFormatEnum() == SPSF_11kHz16BitMono )                        {                            STATSTG Stat;                            hr = pStream->Stat( &Stat, STATFLAG_NONAME );                            ULONG ulNumBytes = Stat.cbSize.LowPart;                                                        if( ulNumBytes > MAXLONG )                            {                                hr = E_OUTOFMEMORY;                            }                                              if( SUCCEEDED( hr ) &&                                fwrite( &ulNumBytes, sizeof(ulNumBytes), 1, hVoiceFile ) )                            {                                BYTE* Buff = (BYTE*)_malloca( ulNumBytes );                                if( SUCCEEDED( hr = pStream->Read( Buff, ulNumBytes, NULL ) ) )                                {                                                           if( !fwrite( Buff, 1, ulNumBytes, hVoiceFile ) )                                    {                                        hr = E_FAIL;                                    }                                }                                _freea( Buff );                            }                            else                            {                                hr = E_FAIL;                            }                        }                        else                        {                            printf( "Input file: %s has wrong wav format.", (LPSTR)CW2A( WordFileName ) );                        }                        pStream->Release();                    }                }                else                {                    hr = E_FAIL;                }            }        }        else        {            hr = E_FAIL;        }        if( SUCCEEDED( hr ) )        {            if( fseek( hVoiceFile, sizeof(dwVersion), SEEK_SET ) ||                !fwrite( &ulNumWords, sizeof(ulNumWords), 1, hVoiceFile ) )            {                hr = E_FAIL;            }        }          if( SUCCEEDED( hr ) )        {            CComPtr<ISpObjectToken> cpToken;            CComPtr<ISpDataKey> cpDataKeyAttribs;            hr = SpCreateNewTokenEx(                    SPCAT_VOICES,                     argv[3],                     &CLSID_SampleTTSEngine,                     L"Sample TTS Voice",                     0x409,                     L"Sample TTS Voice",                     &cpToken,                    &cpDataKeyAttribs);                 if (SUCCEEDED(hr))            {                hr = cpDataKeyAttribs->SetStringValue(L"Gender", L"Male");                if (SUCCEEDED(hr))                {                    hr = cpDataKeyAttribs->SetStringValue(L"Name", L"SampleTTSVoice");                }                if (SUCCEEDED(hr))                {                    hr = cpDataKeyAttribs->SetStringValue(L"Language", L"409");                }                if (SUCCEEDED(hr))                {                    hr = cpDataKeyAttribs->SetStringValue(L"Age", L"Adult");                }                if (SUCCEEDED(hr))                {                    hr = cpDataKeyAttribs->SetStringValue(L"Vendor", L"Microsoft");                }                       CHAR    szFullPath[MAX_PATH * 2];                if (SUCCEEDED(hr) && _fullpath(szFullPath, CW2A(argv[2]), sizeof(szFullPath)/sizeof(szFullPath[0])) == NULL)                {                    hr = SPERR_NOT_FOUND;                }                if (SUCCEEDED(hr))                {                    hr = cpToken->SetStringValue(L"VoiceData", CA2W(szFullPath));                }            }        }        if( hWordList  )        {            fclose( hWordList );        }        if( hVoiceFile )        {            fclose( hVoiceFile );        }        ::CoUninitialize();    }    return FAILED( hr );} TTS引擎头文件#ifndef TtsEngObj_h#define TtsEngObj_h#ifndef __SampleTtsEngine_h__#include "SampleTtsEngine.h"#endif#ifndef SPDDKHLP_h#include <spddkhlp.h>#endif#ifndef SPCollec_h#include <spcollec.h>#endif#include "resource.h"class CSentItem{  public:    CSentItem() { memset( this, 0, sizeof(*this) ); }    CSentItem( CSentItem& Other ) { memcpy( this, &Other, sizeof( Other ) ); }    const SPVSTATE* pXmlState;    LPCWSTR         pItem;    ULONG           ulItemLen;    ULONG           ulItemSrcOffset;            ULONG           ulItemSrcLen;    };typedef CSPList<CSentItem,CSentItem&> CItemList;/*** CTTSEngObj COM 接口 *********************************/class ATL_NO_VTABLE CTTSEngObj :  public CComObjectRootEx<CComMultiThreadModel>, public CComCoClass<CTTSEngObj, &CLSID_SampleTTSEngine>, public ISpTTSEngine,    public ISpObjectWithToken{  public:    DECLARE_REGISTRY_RESOURCEID(IDR_SAMPLETTSENGINE)    DECLARE_PROTECT_FINAL_CONSTRUCT()    BEGIN_COM_MAP(CTTSEngObj)     COM_INTERFACE_ENTRY(ISpTTSEngine)     COM_INTERFACE_ENTRY(ISpObjectWithToken)    END_COM_MAP()  public:    HRESULT FinalConstruct();    void FinalRelease();  public:       STDMETHODIMP SetObjectToken( ISpObjectToken * pToken );    STDMETHODIMP GetObjectToken( ISpObjectToken ** ppToken )        { return SpGenericGetObjectToken( ppToken, m_cpToken ); }    STDMETHOD(Speak)( DWORD dwSpeakFlags,                      REFGUID rguidFormatId, const WAVEFORMATEX * pWaveFormatEx,                      const SPVTEXTFRAG* pTextFragList, ISpTTSEngineSite* pOutputSite );    STDMETHOD(GetOutputFormat)( const GUID * pTargetFormatId, const WAVEFORMATEX * pTargetWaveFormatEx,                                GUID * pDesiredFormatId, WAVEFORMATEX ** ppCoMemDesiredWaveFormatEx );  private:    HRESULT MapFile(const WCHAR * pszTokenValName, HANDLE * phMapping, void ** ppvData );    HRESULT GetNextSentence( CItemList& ItemList );    BOOL    AddNextSentItem( CItemList& ItemList );    HRESULT OutputSentence( CItemList& ItemList, ISpTTSEngineSite* pOutputSite );  private:    CComPtr<ISpObjectToken> m_cpToken;    HANDLE                  m_hVoiceData;    void*                   m_pVoiceData;    VOICEITEM*          m_pWordList;    ULONG               m_ulNumWords;    const SPVTEXTFRAG*  m_pCurrFrag;    const WCHAR*        m_pNextChar;    const WCHAR*        m_pEndChar;    ULONGLONG           m_ullAudioOff;};#endif   TTS资源调用 import "oaidl.idl";import "ocidl.idl";import "sapiddk.idl";typedef struct VOICEITEM{    LPCWSTR pText;    ULONG   ulTextLen;    ULONG   ulNumAudioBytes;    BYTE*   pAudio;} VOICEITEM;[ uuid(7192AA2F-F759-43e9-91E7-226371EF6B2F), version(1.0), helpstring("Sample TTS Engine 1.0 Type Library")]library SAMPLETTSENGLib{ importlib("stdole32.tlb"); importlib("stdole2.tlb"); [  uuid(A832755E-9C2A-40b4-89B2-3A92EE705852),  helpstring("SampleTTSEngine Class") ] coclass SampleTTSEngine {  [default] interface ISpTTSEngine;        interface ISpObjectWithToken; };}; TTS服务框架 #include "stdafx.h"#include "resource.h"#include <initguid.h>#include "SampleTtsEngine.h"#include "SampleTtsEngine_i.c"#include "TtsEngObj.h" CComModule _Module;BEGIN_OBJECT_MAP(ObjectMap)    OBJECT_ENTRY( CLSID_SampleTTSEngine   , CTTSEngObj    )END_OBJECT_MAP() #ifdef _WIN32_WCEextern "C" BOOL WINAPI DllMain(HANDLE hInstance, ULONG dwReason, LPVOID)#elseextern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID #endif{    if (dwReason == DLL_PROCESS_ATTACH)    {        _Module.Init(ObjectMap, (HINSTANCE)hInstance, &LIBID_SAMPLETTSENGLib);    }    else if (dwReason == DLL_PROCESS_DETACH)        _Module.Term();    return TRUE;    } STDAPI DllCanUnloadNow(void){    return (_Module.GetLockCount()==0) ? S_OK : S_FALSE;} STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv){    return _Module.GetClassObject(rclsid, riid, ppv);} STDAPI DllRegisterServer(void){    return _Module.RegisterServer(TRUE);} STDAPI DllUnregisterServer(void){    return _Module.UnregisterServer(TRUE);}TTS预留接口EXPORTS DllCanUnloadNow     PRIVATE DllGetClassObject   PRIVATE DllRegisterServer   PRIVATE DllUnregisterServer PRIVATE    /********************************************************************************TTS引擎实现********************************************************************************/#include "stdafx.h"#include "TtsEngObj.h" /******************************************************************************----------------------------* *描述: *构造*****************************************************************************/HRESULT CTTSEngObj::FinalConstruct(){    HRESULT hr = S_OK;    m_hVoiceData = NULL;    m_pVoiceData = NULL;    m_pWordList  = NULL;    m_ulNumWords = 0;    return hr;} void CTTSEngObj::FinalRelease(){    delete m_pWordList;    if( m_pVoiceData )    {        ::UnmapViewOfFile( (void*)m_pVoiceData );    }    if( m_hVoiceData )    {        ::CloseHandle( m_hVoiceData );    }} HRESULT CTTSEngObj::MapFile( const WCHAR * pszTokenVal,                              HANDLE * phMapping,                                      void ** ppvData )            {    HRESULT hr = S_OK;    CSpDynamicString dstrFilePath;    hr = m_cpToken->GetStringValue( pszTokenVal, &dstrFilePath );    if ( SUCCEEDED( hr ) )    {        bool fWorked = false;        *phMapping = NULL;        *ppvData = NULL;        HANDLE hFile;#ifdef _WIN32_WCE        hFile = CreateFileForMapping( dstrFilePath, GENERIC_READ,                                      FILE_SHARE_READ, NULL, OPEN_EXISTING,                                      FILE_ATTRIBUTE_NORMAL, NULL );#else        hFile = CreateFile( CW2T(dstrFilePath), GENERIC_READ,                            FILE_SHARE_READ, NULL, OPEN_EXISTING,                            FILE_ATTRIBUTE_NORMAL, NULL );#endif        if (hFile != INVALID_HANDLE_VALUE)        {            *phMapping = ::CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, 0, NULL );            if (*phMapping)            {                *ppvData = ::MapViewOfFile( *phMapping, FILE_MAP_READ, 0, 0, 0 );                if (*ppvData)                {                    fWorked = true;                }            }            ::CloseHandle( hFile );        }        if (!fWorked)        {            hr = HRESULT_FROM_WIN32(::GetLastError());            if (*phMapping)            {                ::CloseHandle(*phMapping);                *phMapping = NULL;            }        }    }    return hr;}STDMETHODIMP CTTSEngObj::SetObjectToken(ISpObjectToken * pToken){    HRESULT hr = SpGenericSetObjectToken(pToken, m_cpToken);      if( SUCCEEDED( hr ) )    {        hr = MapFile( L"VoiceData", &m_hVoiceData, &m_pVoiceData );    }    if( SUCCEEDED( hr ) )    {        delete m_pWordList;        UNALIGNED DWORD* pdwPtr = (UNALIGNED DWORD*)m_pVoiceData;        if( *pdwPtr++ != 1 )        {            hr = E_INVALIDARG;            _ASSERT(0);        }            if( SUCCEEDED( hr ) )        {            m_ulNumWords = *pdwPtr++;        }        m_pWordList = new VOICEITEM[m_ulNumWords];        if( !m_pWordList )        {            hr = E_OUTOFMEMORY;        }        else        {            for( ULONG i = 0; i < m_ulNumWords; ++i )            {                ULONG ulTextByteLen = *pdwPtr++;                m_pWordList[i].pText = (UNALIGNED LPCWSTR)pdwPtr;                m_pWordList[i].ulTextLen = (ulTextByteLen / sizeof(WCHAR)) - 1;                pdwPtr = (UNALIGNED DWORD*)(((BYTE*)pdwPtr) + ulTextByteLen);                m_pWordList[i].ulNumAudioBytes = *pdwPtr++;                m_pWordList[i].pAudio = (BYTE*)pdwPtr;                pdwPtr = (UNALIGNED DWORD*)(((BYTE*)pdwPtr) + m_pWordList[i].ulNumAudioBytes);            }        }    }    return hr;}  /****************************************************************************** CTTSEngObj : :说话* *-------------------* *描述: *这是主要的方法的SAPI要求提供的案文。 *------------------------------------------------- ---------------------------- *输入参数 * * pUser *指针当前的用户配置文件对象。这个对象包含 *信息,如哪些语言和正在使用此对象 *还提供获得资源,如掌握词汇的SAPI对象。 * * dwSpeakFlags *这是一套用来控制旗帜的行为 *的SAPI语音对象和相关的发动机。 * * VoiceFmtIndex *零基础的索引指定的输出格式,应 *用于在渲染。 * * pTextFragList *一个链表的文字片段将会作出。有 *每一个片段的XML状态的变化。如果输入文本并 *不包含任何的XML标记,将只有一个单一的片段。 * * pOutputSite *该接口返回的SAPI ,所有输出的音频样本和事件是书面。 * *返回值 * S_OK -这应该是成功的渲染后返回,或者如果 *渲染被打断,因为* pfContinue更改为FALSE 。 * E_INVALIDARG ******************************************************************************/STDMETHODIMP CTTSEngObj::Speak( DWORD dwSpeakFlags,                                REFGUID rguidFormatId,                                const WAVEFORMATEX * pWaveFormatEx,                                const SPVTEXTFRAG* pTextFragList,                                ISpTTSEngineSite* pOutputSite ){    HRESULT hr = S_OK;    if( SP_IS_BAD_INTERFACE_PTR( pOutputSite ) ||        SP_IS_BAD_READ_PTR( pTextFragList )  )    {        hr = E_INVALIDARG;    }    else    {        m_pCurrFrag   = pTextFragList;        m_pNextChar   = m_pCurrFrag->pTextStart;        m_pEndChar    = m_pNextChar + m_pCurrFrag->ulTextLen;        m_ullAudioOff = 0;        CItemList ItemList;        while( SUCCEEDED( hr ) && !(pOutputSite->GetActions() & SPVES_ABORT) )        {            if( pOutputSite->GetActions() & SPVES_SKIP )            {                long lSkipCnt;                SPVSKIPTYPE eType;                hr = pOutputSite->GetSkipInfo( &eType, &lSkipCnt );                if( SUCCEEDED( hr ) )                {                            hr = pOutputSite->CompleteSkip( 0 );                }            }            if( SUCCEEDED( hr ) && (hr = GetNextSentence( ItemList )) != S_OK )            {                break;                            }             if( !(pOutputSite->GetActions() & SPVES_ABORT) )            {                CSentItem& FirstItem = ItemList.GetHead();                CSentItem& LastItem  = ItemList.GetTail();                CSpEvent Event;                Event.eEventId             = SPEI_SENTENCE_BOUNDARY;                Event.elParamType          = SPET_LPARAM_IS_UNDEFINED;                Event.ullAudioStreamOffset = m_ullAudioOff;                Event.lParam               = (LPARAM)FirstItem.ulItemSrcOffset;                Event.wParam               = (WPARAM)LastItem.ulItemSrcOffset +                                                     LastItem.ulItemSrcLen -                                                     FirstItem.ulItemSrcOffset;                hr = pOutputSite->AddEvents( &Event, 1 );                if( SUCCEEDED( hr ) )                {                    hr = OutputSentence( ItemList, pOutputSite );                }            }        }        if( hr == S_FALSE )        {            hr = S_OK;        }    }    return hr;}HRESULT CTTSEngObj::OutputSentence( CItemList& ItemList, ISpTTSEngineSite* pOutputSite ){    HRESULT hr = S_OK;    ULONG WordIndex;    SPLISTPOS ListPos = ItemList.GetHeadPosition();    while( ListPos && !(pOutputSite->GetActions() & SPVES_ABORT) )    {        CSentItem& Item = ItemList.GetNext( ListPos );        switch( Item.pXmlState->eAction )        {          case SPVA_Speak:          {             if( iswalpha( Item.pItem[0] ) || iswdigit( Item.pItem[0] ) )            {                for( WordIndex = 0; WordIndex < m_ulNumWords; ++WordIndex )                {                    if( ( m_pWordList[WordIndex].ulTextLen == Item.ulItemLen ) &&                        ( !_wcsnicmp( m_pWordList[WordIndex].pText, Item.pItem, Item.ulItemLen )) )                    {                        break;                    }                }                if( WordIndex == m_ulNumWords )                {                    WordIndex = 0;                }                CSpEvent Event;                Event.eEventId             = SPEI_WORD_BOUNDARY;                Event.elParamType          = SPET_LPARAM_IS_UNDEFINED;                Event.ullAudioStreamOffset = m_ullAudioOff;                Event.lParam               = Item.ulItemSrcOffset;                Event.wParam               = Item.ulItemSrcLen;                pOutputSite->AddEvents( &Event, 1 );                hr = pOutputSite->Write( m_pWordList[WordIndex].pAudio,                                         m_pWordList[WordIndex].ulNumAudioBytes,                                         NULL );                m_ullAudioOff += m_pWordList[WordIndex].ulNumAudioBytes;            }          }          break;          case SPVA_Silence:          {            BYTE Buff[1000];            memset( Buff, 0, 1000 );            ULONG NumSilenceBytes = Item.pXmlState->SilenceMSecs * 22;            while( !(pOutputSite->GetActions() & SPVES_ABORT) )            {                if( NumSilenceBytes > 1000 )                {                    hr = pOutputSite->Write( Buff, 1000, NULL );                    NumSilenceBytes -= 1000;                }                else                {                    hr = pOutputSite->Write( Buff, NumSilenceBytes, NULL );                    break;                }            }            m_ullAudioOff += NumSilenceBytes;          }          break;          case SPVA_Bookmark:          {            WCHAR * pszBookmark = (WCHAR *)_malloca((Item.ulItemLen + 1) * sizeof(WCHAR));            memcpy(pszBookmark, Item.pItem, Item.ulItemLen * sizeof(WCHAR));            pszBookmark[Item.ulItemLen] = 0;            SPEVENT Event;            Event.eEventId             = SPEI_TTS_BOOKMARK;            Event.elParamType          = SPET_LPARAM_IS_STRING;            Event.ullAudioStreamOffset = m_ullAudioOff;            Event.lParam               = (LPARAM)pszBookmark;            Event.wParam               = _wtol(pszBookmark);            hr = pOutputSite->AddEvents( &Event, 1 );            _freea(pszBookmark);          }          break;          case SPVA_Pronounce:                break;          case SPVA_ParseUnknownTag:               break;        }    }    return hr;} /* CTTSEngObj::OutputSentence */STDMETHODIMP CTTSEngObj::GetOutputFormat( const GUID * pTargetFormatId, const WAVEFORMATEX * pTargetWaveFormatEx,                                          GUID * pDesiredFormatId, WAVEFORMATEX ** ppCoMemDesiredWaveFormatEx ){    HRESULT hr = S_OK;    hr = SpConvertStreamFormatEnum(SPSF_11kHz16BitMono, pDesiredFormatId, ppCoMemDesiredWaveFormatEx);    return hr;}HRESULT CTTSEngObj::GetNextSentence( CItemList& ItemList ){    HRESULT hr = S_OK;    ItemList.RemoveAll();    if( m_pCurrFrag == NULL )    {        hr = S_FALSE;    }    else    {        BOOL fSentDone = false;        BOOL fGoToNextFrag = false;        while( m_pCurrFrag && !fSentDone )        {            if( m_pCurrFrag->State.eAction == SPVA_Speak )            {                fSentDone = AddNextSentItem( ItemList );                     if( m_pNextChar >= m_pEndChar )                {                    fGoToNextFrag = true;                }            }            else            {                      CSentItem Item;                Item.pItem           = m_pCurrFrag->pTextStart;                Item.ulItemLen       = m_pCurrFrag->ulTextLen;                Item.ulItemSrcOffset = m_pCurrFrag->ulTextSrcOffset;                Item.ulItemSrcLen    = Item.ulItemLen;                Item.pXmlState       = &m_pCurrFrag->State;                ItemList.AddTail( Item );                fGoToNextFrag = true;            }            if( fGoToNextFrag )            {                fGoToNextFrag = false;                m_pCurrFrag = m_pCurrFrag->pNext;                if( m_pCurrFrag )                {                    m_pNextChar = m_pCurrFrag->pTextStart;                    m_pEndChar  = m_pNextChar + m_pCurrFrag->ulTextLen;                }                else                {                    m_pNextChar = NULL;                    m_pEndChar  = NULL;                }            }        }         if( ItemList.IsEmpty() )        {            hr = S_FALSE;        }    }    return hr;} static BOOL IsSpace( WCHAR wc ){    return ( ( wc == 0x20 ) || ( wc == 0x9 ) || ( wc == 0xD  ) || ( wc == 0xA ) );}static const WCHAR* SkipWhiteSpace( const WCHAR* pPos ){    while( IsSpace( *pPos ) ) ++pPos;    return pPos;}static const WCHAR*     FindNextToken( const WCHAR* pStart, const WCHAR* pEnd, const WCHAR*& pNext ){    const WCHAR* pPos = SkipWhiteSpace( pStart );    pNext = pPos;    if( pNext == pEnd )    {        pPos = NULL;    }    else    {        while( *pNext && !IsSpace( *pNext ) )        {            if( ++pNext == pEnd )            {                             break;            }        }    }    return pPos;} BOOL SearchSet( WCHAR wc, const WCHAR* Set, ULONG Count, ULONG* pIndex ){    for( ULONG i = 0; i < Count; ++i )    {        if( wc == Set[i] )        {            *pIndex = i;            return true;        }    }    return false;}BOOL CTTSEngObj::AddNextSentItem( CItemList& ItemList ){    ULONG ulIndex;    CSentItem Item;    Item.pItem = FindNextToken( m_pNextChar, m_pEndChar, m_pNextChar );     if( Item.pItem == NULL )    {        return false;    }    const WCHAR* pTrailChar = m_pNextChar-1;    ULONG TokenLen = (ULONG)(m_pNextChar - Item.pItem);    static const WCHAR LeadItems[] = { L'(', L'/"', L'{', L'/'', L'[' };    while( TokenLen > 1 )    {        if( SearchSet( Item.pItem[0], LeadItems, sp_countof(LeadItems), &ulIndex ) )        {            CSentItem LItem;            LItem.pItem           = Item.pItem;            LItem.ulItemLen       = 1;            LItem.pXmlState       = &m_pCurrFrag->State;            LItem.ulItemSrcLen    = LItem.ulItemLen;            LItem.ulItemSrcOffset = m_pCurrFrag->ulTextSrcOffset +                                    (ULONG)( LItem.pItem - m_pCurrFrag->pTextStart );            ItemList.AddTail( LItem );            ++Item.pItem;            --TokenLen;        }        else        {            break;        }    }    SPLISTPOS ItemPos = ItemList.AddTail( Item );    static const WCHAR EOSItems[] = { L'.', L'!', L'?' };    static const WCHAR TrailItems[] = { L',', L'/"', L';', L':', L')', L'}', L'/'', L']' };    BOOL fIsEOS = false;    while( TokenLen > 1 )    {        BOOL fAddTrailItem = false;        if( SearchSet( *pTrailChar, EOSItems, sp_countof(EOSItems), &ulIndex ) )        {            fIsEOS = true;            fAddTrailItem = true;        }        else if( SearchSet( *pTrailChar, TrailItems, sp_countof(TrailItems), &ulIndex ) )        {            fAddTrailItem = true;        }        if( fAddTrailItem )        {            CSentItem TItem;            TItem.pItem           = pTrailChar;            TItem.ulItemLen       = 1;            TItem.pXmlState       = &m_pCurrFrag->State;            TItem.ulItemSrcLen    = TItem.ulItemLen;            TItem.ulItemSrcOffset = m_pCurrFrag->ulTextSrcOffset +                                    (ULONG)( TItem.pItem - m_pCurrFrag->pTextStart );            ItemList.InsertAfter( ItemPos, TItem );            --TokenLen;            --pTrailChar;        }        else        {            break;        }    }    if( *m_pNextChar == NULL )    {        fIsEOS = true;        if( !SearchSet( *(m_pNextChar-1), EOSItems, sp_countof(EOSItems), &ulIndex ) )        {            static const WCHAR* pPeriod = L".";            CSentItem EOSItem;            EOSItem.pItem           = pPeriod;            EOSItem.ulItemLen       = 1;            EOSItem.pXmlState       = &m_pCurrFrag->State;            EOSItem.ulItemSrcLen    = EOSItem.ulItemLen;            EOSItem.ulItemSrcOffset = m_pCurrFrag->ulTextSrcOffset +                                    (ULONG)( (m_pNextChar-1) - m_pCurrFrag->pTextStart );            ItemList.AddTail( EOSItem );        }    }    else if( pTrailChar[1] == L'.' )    {         }        for( ULONG i = 0; i < TokenLen; ++i )    {        if( Item.pItem[i] == L'/'' )        {            ((WCHAR)Item.pItem[i]) = L'_';        }    }    if( TokenLen > 0 )    {        Item.ulItemLen       = TokenLen;        Item.pXmlState       = &m_pCurrFrag->State;        Item.ulItemSrcLen    = Item.ulItemLen;        Item.ulItemSrcOffset = m_pCurrFrag->ulTextSrcOffset +                               (ULONG)( Item.pItem - m_pCurrFrag->pTextStart );        ItemList.SetAt( ItemPos, Item );    }    return fIsEOS;}   

           

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.youkuaiyun.com/jiangjunshow

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值