srt字幕解析(上)

本文主要讲解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字幕的解析就完啦,以上全属本人见解,如有什么不对的地方可以私信我告诉我哦~

Published by

风君子

独自遨游何稽首 揭天掀地慰生平