Search code examples
c++regexyoutube-apiatl

Match more than one group with CAtlRegExp


I am trying to get total duration of a youtube playlist using youtube data api. I download response from, for example, http://gdata.youtube.com/feeds/api/playlists/63F0C78739B09958 and my idea is to iterate over each <yt:duration='xxx'/> occurences where xxx is each video duration in seconds, and sum them up to get total playlist runtime.

For getting each i use CAtlRegExp with the following string:

<yt:duration seconds='{[0-9]+}'/>

however it matches only the first occurence, not any of the rest (referring to the source code pasted below, the loop iterates only once).

I tried some other regex strings like

  • (<yt:duration seconds='{[0-9]+}'/>)

  • (<yt:duration seconds='{[0-9]+}'/>)*

however they didn't work either (the same reason).

Here is an extract from source code, where the for loop only iterates once because mcDuration.m_uNumGroups equals to 1:

    //get video duration
    CAtlRegExp<> reDurationFinder;
    CAtlREMatchContext<> mcDuration; 

    REParseError status = reDurationFinder.Parse(_T("<yt:duration seconds='{[0-9]+}'/>"));

    if ( status != REPARSE_ERROR_OK )
    {
        // Unexpected error.
        return false;
    }

    if ( !reDurationFinder.Match(sFeed, &mcDuration) ) //i checked it with debug, sFeed contains full response from youtube data api
    {
        //cannot find video url
        return false;
    }

    m_nLengthInSeconds = 0;
    for ( UINT nGroupIndex = 0; nGroupIndex < mcDuration.m_uNumGroups; ++nGroupIndex )
    {
        const CAtlREMatchContext<>::RECHAR* szStart = 0;
        const CAtlREMatchContext<>::RECHAR* szEnd = 0;
        mcDuration.GetMatch(nGroupIndex, &szStart, &szEnd);

        ptrdiff_t nLength = szEnd - szStart;
        m_nLengthInSeconds += _ttoi(CString(szStart, nLength));
    }

How can I make CAtlRegExp match all of the occurences of <yt:duration ... ?


Solution

  • You will always have the first (next) occurrence only. To find others you need to keep Match'ing in a loop until no more occurrences found.

        for(; ; )
        {
            CAtlREMatchContext<> MatchContext;
            pszNextText = NULL;
            if(!Expression.Match(pszText, &MatchContext, &pszNextText))
                break;
            // Here you process the found occurrence
            pszText = pszNextText;
        }