首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

VC++ 使用 Script 正則表達式解析 LRC 歌詞

     編輯:VC 教學

背景

LRC 歌詞文件包含時間標籤 [mm:ss.xx] 及元資料標籤 [ti:標題]、[ar:歌手]、[al:專輯] 等。本文示範在 VC++ 中引入 Microsoft Script Control (VBScript.RegExp) 以正則表達式高效提取結構化資訊。

核心類設計

class LRCOBJECT
{
public:
    CString m_strTitle, m_strArtist, m_strAlbum;
    // 時間-歌詞映射表
    CMap<long, long, CString, CString&> m_mapLyrics; // key: 毫秒數

    LRCOBJECT(const char* pText) { Parse(pText); }
    void Parse(const char* pText);
};

關鍵實現:Parse 方法

void LRCOBJECT::Parse(const char* pText)
{
    USES_CONVERSION;
    // 初始化 COM (單執行緒模型)
    CoInitialize(NULL);

    try {
        // 建立 RegExp 物件
        IRegExpPtr pRegExp(__uuidof(RegExp));
        pRegExp->PutGlobal(VARIANT_TRUE);
        pRegExp->PutIgnoreCase(VARIANT_TRUE);

        // 1. 提取元資料標籤 [ti:...] [ar:...] [al:...]
        auto ExtractTag = [&](LPCTSTR pattern, CString& dest) {
            pRegExp->PutPattern(_bstr_t(pattern));
            IMatchCollectionPtr pMatches = pRegExp->Execute(_bstr_t(pText));
            if (pMatches->GetCount() > 0) {
                IMatchPtr pMatch = pMatches->GetItem(0);
                ISubMatchesPtr pSub = pMatch->GetSubMatches();
                dest = (LPCTSTR)(_bstr_t)pSub->GetItem(0); // 子匹配組 1
            }
        };

        ExtractTag(_T("\\[ti:([^\\]]+)\\]"), m_strTitle);
        ExtractTag(_T("\\[ar:([^\\]]+)\\]"), m_strArtist);
        ExtractTag(_T("\\[al:([^\\]]+)\\]"), m_strAlbum);

        // 2. 提取時間-歌詞行:\[(\d{2}):(\d{2})[.:](\d{2})\](.*)
        pRegExp->PutPattern(_T("\\[(\\d{2}):(\\d{2})[.:](\\d{2})\\](.*)"));
        IMatchCollectionPtr pLines = pRegExp->Execute(_bstr_t(pText));
        long count = pLines->GetCount();
        for (long i = 0; i < count; ++i) {
            IMatchPtr pLine = pLines->GetItem(i);
            ISubMatchesPtr pSub = pLine->GetSubMatches();
            int min = _wtoi((LPCTSTR)(_bstr_t)pSub->GetItem(0));
            int sec = _wtoi((LPCTSTR)(_bstr_t)pSub->GetItem(1));
            int ms  = _wtoi((LPCTSTR)(_bstr_t)pSub->GetItem(2));
            CString lyric = (LPCTSTR)(_bstr_t)pSub->GetItem(3);
            long totalMs = (min * 60 + sec) * 1000 + ms * 10; // 兩位小數 -> 毫秒
            m_mapLyrics.SetAt(totalMs, lyric.Trim());
        }
    }
    catch (_com_error& e) {
        TRACE(_T("LRC 解析錯誤: %s\n"), e.ErrorMessage());
    }
    CoUninitialize();
}

關鍵點解析

  • IRegExpPtr 等智慧指標來自 #import <mscript.ocx> 或 scrrun.dll。
  • 正則中 (...) 為捕獲組,對應 ISubMatches 索引 0,1,2...。
  • _bstr_t 自動處理 ANSI/Unicode 轉換,配合 USES_CONVERSION 宏。
  • 時間標籤支援 mm:ss.xx 與 mm:ss:xx 兩種分隔符。

現代替代方案

若專案已使用 C++11+,建議改用 std::regex (需 GCC 4.9+/MSVC 2013+) 或第三方 PCRE2、RE2,移除 COM 依賴,提升跨平台性與效能:

std::regex meta_re(R"(\[(ti|ar|al):([^\]]+)\])");
std::regex line_re(R"(\[(\d{2}):(\d{2})[.:](\d{2})\](.*))");
// 使用 std::sregex_iterator 迭代匹配...

應用場景

  • 本地音樂播放器歌詞同步顯示
  • KTV 點歌系統歌詞預處理
  • 歌詞文字檢索、關鍵字標雲生成
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved