LRC,SRT 字幕文件解析

字幕数据节点:

// 字幕数据节点定义
struct SSubtitleDataNode
{
	__int64 nBeginTime;
	__int64 nEndTime;
	QString strText;

	SSubtitleDataNode() {
		nBeginTime = -1;
		nEndTime = -1;
	}

	SSubtitleDataNode(__int64 nBegin, __int64 nEnd, const QString &str)
		: nBeginTime(nBegin)
		, nEndTime(nEnd)
		, strText(str)
	{
	}
};

区分编码格式:

QString FindFileCode(const QString &fileName)
{
	QFile file(fileName);
	if (file.open(QIODevice::ReadOnly)) 
	{
		QByteArray buff = file.readLine();

		QTextCodec::ConverterState state;
		QTextCodec *codec = QTextCodec::codecForName("UTF-8");
		QString text = codec->toUnicode(buff.constData(), buff.size(), &state);
		if (state.invalidChars > 0)
			return QString("GBK");
		else
			return QString("UTF8");

		file.close();
	}
	return "GBK";
}

LRC文件解析:

QString strCodeType = FindFileCode(strPath);
__int64 nMediaDuration = -1;

// 读取文件
QFile file(strPath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
	return;
QTextStream stream(&file);
stream.setCodec(strCodeType.toStdString().c_str());  //设置QTextStream对象的编码格式
QString readStr = stream.readAll();
file.close();

QRegularExpression rex("\\[(\\d+?:\\d+\\.\\d+)?\\]([^\r\n]*)"); // 正则表达式
QRegularExpressionMatch match = rex.match(readStr);
if (!match.hasMatch())	// 不支持本格式
	return;

QRegularExpressionMatchIterator globalMatch = rex.globalMatch(readStr);
while (globalMatch.hasNext())
{
	QRegularExpressionMatch item = globalMatch.next();
	SSubtitleDataNode node;
	for (int i = 0; i <= item.lastCapturedIndex(); i++)
	{
		auto strContent = item.captured(i);
		if (strContent.isEmpty())
			continue;

		switch (i)
		{
		case 0:	// 所有内容
			break;
		case 1: // 开始时间
		{
			QTime tBegin = QTime::fromString(strContent, "mm:ss.z");
			if (tBegin.msec() == -1)
				break;
			node.nBeginTime = (tBegin.minute() * 60 + tBegin.second()) * 1000 + tBegin.msec();
		}
		break;
		default: // 内容
		{
			if (!node.strText.isEmpty())
				node.strText += "\n";
			node.strText += strContent;
		}
		break;
		}
	}

	if (node.strText.isEmpty() && !vecDatas.empty())	// 有些格式为第二行只有时间,为上一行的显示结束时间
		vecDatas[vecDatas.size() - 1].nEndTime = node.nBeginTime;
	else if (node.nBeginTime != -1)
		vecDatas.push_back(node);
}

// 处理字幕结束时间,若是文件中未单独给出,则上一条字幕的结束时间为下下一条字幕的开始时间
for (int i = (int)vecDatas.size() - 1; i >= 0; i--)
{
	if (vecDatas[i].nEndTime == -1)
	{
		if (i == (int)vecDatas.size() - 1)
			vecDatas[i].nEndTime = vecDatas[i].nBeginTime + DEFAULT_ENDTEXT_DURATION;
		else
			vecDatas[i].nEndTime = vecDatas[i + 1].nBeginTime;
	}

	nMediaDuration = std::max(nMediaDuration, vecDatas[i].nEndTime);
}

SRT文件解析:

QString strCodeType = FindFileCode(strPath);
__int64 nMediaDuration = -1;

// 读取文件
QFile file(strPath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
	return;
QTextStream stream(&file);
stream.setCodec(strCodeType.toStdString().c_str());  //设置QTextStream对象的编码格式
QString readStr = stream.readAll();
file.close();

QRegularExpression rex("(\\d+)?\n(\\d+:\\d+:\\d+,\\d+) --> (\\d+:\\d+:\\d+,\\d+)(\\d*(?:\r?(?!\r?).*)*)\n(.*(?:\r?\n(?!\r?\n).*)*)"); // 正则表达式
QRegularExpressionMatch match = rex.match(readStr);
if (!match.hasMatch())	// 不支持本格式
	return;

QRegularExpressionMatchIterator globalMatch = rex.globalMatch(readStr);
while (globalMatch.hasNext())
{
	QRegularExpressionMatch item = globalMatch.next();
	SSubtitleDataNode node;
	for (int i = 0; i <= item.lastCapturedIndex(); i++)
	{
		auto strContent = item.captured(i);
		if(strContent.isEmpty())
			continue;

		switch (i)
		{
		case 0:	// 所有内容
			break;
		case 1:	// 序号
			break;
		case 2: // 开始时间
		{
			QTime tBegin = QTime::fromString(strContent, "hh:mm:ss,zzz");
			if (tBegin.msec() == -1)
				break;
			node.nBeginTime = (tBegin.hour() * 3600 + tBegin.minute() * 60 + tBegin.second()) * 1000 + tBegin.msec();
		}
		break;
		case 3: // 结束时间
		{
			QTime tEnd = QTime::fromString(strContent, "hh:mm:ss,zzz");
			if (tEnd.msec() == -1)
				break;
			node.nEndTime = (tEnd.hour() * 3600 + tEnd.minute() * 60 + tEnd.second()) * 1000 + tEnd.msec();
			nMediaDuration = std::max(nMediaDuration, node.nEndTime);
		}
		break;
		default: // 内容
		{
			if(!node.strText.isEmpty())
				node.strText += "\n";
			node.strText += strContent;
		}
		break;
		}
	}

	if (node.nBeginTime != -1 && node.nEndTime != -1)
		vecDatas.push_back(node);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值