本文主要讲解srt字幕文件的加载和格式解析,使用c++解析srt为我们需要的表达形式和格式。
1、srt格式文件为视频字幕文件,其格式为:
数字
时间 –> 时间
字幕内容(可以多行)
空行
数字
时间 –> 时间
字幕内容(可以多行)
空行
例子:
1
00:00:00,162 –> 00:00:01,875
This story is inspired by real events
in France in the late 19th century.
2
00:00:02,800 –> 00:00:03,000
<b>previously, on amc's "Feed the beast…</b>
3
00:00:06,560 –> 00:00:11,520
{an4}{pos(57.12,210.56)}翻譯:肉松 小酸奶 圈圈 Silence
4
00:00:11,560 –> 00:00:15,760
<b><u><font color='RED'>{an4}{pos(70,211.2)}文本</font></u></b>
<b><u><font color='RED'>文本</font></u></b>
<b><u><font color='RED'>文本</font></u></b>
<b><u><font color='RED'>文本</font></u></b>
2、解析
根据每个字幕段所包含的内容定义结构体:
struct sSubRipText
{int order; //序号CString szStart; //开始时间CString szEnd; //结束时间CString szText; //内容/*DWORD dwTextColor; //可用来存储解析字幕格式int nAlignment;int fontSize;CString strFontName;*/sSubRipText(){order = 0;//dwTextColor = 0xffffff;szStart.Empty();szEnd.Empty();szText.Empty();}
};
定义结构体数组:
typedef CArray<sSubRipText,sSubRipText&> CArraySrt;
我的思路是:读取srt字幕文本文件,逐行读取,存到一个字符串数组中,每当遇到空行时,解析这一段字符串,清空字符串数组,直到读取到文本末尾。
读取文件代码为:
BOOL CSubtitleOperate::LoadSrt(LPCTSTR lpFilepath,CArrayScene& arrScene)
{arrScene.RemoveAll();CString filePath(lpFilepath);if (!IsFileExist(filePath))return FALSE;CString lineCurText,lineNextText;CStdioFileEx file;if(!file.Open(filePath,CFile::modeRead|CFile::shareDenyRead| CFile::typeText))return FALSE;int nPos = -1;BOOL bStop= TRUE;CArraySrt arrSrt;CStringArray strArray;strArray.RemoveAll();while(bStop){bStop =file.ReadString(lineCurText);if (!bStop){if(strArray.GetCount()>0){ParseOneSrt(arrSrt,strArray);strArray.RemoveAll();}break;}if(!lineCurText.IsEmpty()){strArray.Add(lineCurText);}else{ParseOneSrt(arrSrt,strArray);strArray.RemoveAll();}}SrtToScene(arrScene,arrSrt);file.Close();return TRUE;
}
把每一个字幕当成一个字幕段,首先解析一个字幕段:
void CSubtitleOperate::ParseOneSrt(CArraySrt& arrSrt,CStringArray& strArray)
{int nCount = strArray.GetCount();if(nCount == 0)return;int nline = 0; //用来计数当前解析到第几行sSubRipText srtItem;if(IsDigit(strArray.GetAt(nline))){srtItem.order = _ttoi(strArray.GetAt(0));nline++;}if(nline+1>nCount)return;CString strTime = strArray.GetAt(nline);int npos = strTime.Find(_T("-->"));if(npos != -1){srtItem.szStart = strTime.Left(npos-1); //将-->之前的字符串存在开始时间中,之后的放在结束时间中srtItem.szEnd = strTime.Mid(npos+4); nline++;}if(nCount>nline) //多次判断是为了没有字符串而导致getAt错误{srtItem.szText = strArray.GetAt(nline);nline++;}for(int i = nline; i<nCount;i++){srtItem.szText += _T("rn") + strArray.GetAt(i); }ParseSrtFormat(srtItem);arrSrt.Add(srtItem);
}
解析每一段字幕格式:
void CSubtitleOperate::ParseSrtFormat(sSubRipText& srtItem)
{CString strText = srtItem.szText;if(strText.IsEmpty())return;int nStart = 0;int npos1 = strText.Find('<',nStart);int npos2 = strText.Find('>',nStart);while(-1 != npos1 && -1 != npos2){if(strText.Delete(npos1,npos2-npos1+1)<=0)break;npos1 = strText.Find('<',nStart);npos2 = strText.Find('>',nStart);}npos1 = strText.Find('{',nStart);npos2 = strText.Find('}',nStart);while(-1 != npos1 && -1 != npos2){if(strText.Delete(npos1,npos2-npos1+1)<=0)break;npos1 = strText.Find('{',nStart);npos2 = strText.Find('}',nStart);}srtItem.szText = strText;
}
解析格式时由于我不需要字幕本身的格式,所以我直接去掉了,如果需要,可以了解srt字幕文件的格式方式解析字幕所附带的格式控制符号。
在此,srt字幕的解析就完啦,以上全属本人见解,如有什么不对的地方可以私信我告诉我哦~