批量修改字幕文件中的时间,c语言实现

最近迷上了一部美剧,权力的游戏 ,Game of Thrones.追到了第三季。可惜下到的版本都是中文字幕或者中英字幕。作为一个自以为英语还不错的人,怎么能看中文字幕呢,中英字幕也是不行的。 不看纯英文的字幕,逼格真是太低了。
可惜,能下载的带字幕的版本都是中文字幕或者中英字幕。没办法,只有下了一个不带字幕的版本,然后自己再去找纯英文的字幕。
好不容易把电视剧视频文件和纯英文字幕凑齐了,正准备在纯英文的语境中欣赏呢,发生了一件让我吐血的意外。字幕的时间和视频的时间是不匹配的。暴风影音的微调字幕的功能,最多也不能超过一分钟。然而,这个字幕和视频的时间差足有两分多钟,大概是字幕对应的那个视频裁掉了片头吧。照着字幕的名字去搜视频,也没有搜到。看来只能修改字幕中语句的时间了。

时间一旦错了,每句对话的文本的时间都要修改,如果手动去修改的话,还不把人给累死,把字幕改好了,也没有欣赏电影的欲望了。这种重复的程序化工作,不就是应该用计算机编程来解决吗?看来我学了这么长时间的c语言,现在可以派上用场了。有点小兴奋。

大概思路是,根据视频中的某个语句和时间,在字幕文件中找出对应的语句和时间,两个时间的差值就是声音与字幕的时间差,记录这个时间差。逐一读取原字幕文件中的字符,如果是非时间的字符,将其原封不动的复制写入另一个文件中;如果是显示时间的字符,则对其进行必要的修改,加上时间差,将修改后的时间字符串写入新字幕文件中。

因为我用的标准c,仅支持ANSI字符集,又是纯英文字符,ANSI编码也足够了。字幕文件拷贝到c盘下,我假定你是一定有c盘的,用记事本打开,另存为ANSI编码格式,不要理会警告。

这样的话,字幕文件里的所有字符c语言都可以处理了。

就可以用fopen()函数打开和创建。

运行我的代码后,在输入框里根据提示输入文件名。我的代码会自动拼接上路径名和后缀名,在c语言中,这才是完整的文件名。


这里面的关键问题是,要修改时间,那么如何标定时间字符串?仔细观察字幕文件。

1
00:02:13,110 --> 00:02:15,879
<i>Fall back!</i>


2
00:03:02,662 --> 00:03:04,463
Brother?


3
00:04:25,646 --> 00:04:28,314
Did you send the ravens?


很容易发现,形如xx:xx:xx的时间字符串,最显著的特征就是冒号。于是,打开字幕文件后,就用':'来标定时间。用习语while( (ch=fgetc(fp)) != EOF )逐一读字符,读到':'之后,停下来,进行修正时间的操作;如果读的不是':',即与时间无关的字符,则用fputc(ch,fp1)将字符原封不动写入新文件中,fp1是写入文件的指针。

第一次读到':’之后,代表读的是分钟之前的':',那么将读文件的内位指针(这是我自己起的名字,代表文件信息结构体内指示当前读指针位置的值)往后退3个字符长度,退到小时之前,即整个时间字符串之前,用文件扫描格式函数fsanf(fp,"%2d:%2d:%2d",&th,&tm,&ts)对整个时间字符串xx:xx:xx进行扫描,得到时间后,进行修正,再用文件打印格式函数fprintf向写文件中打印整个时间字符串。因此,也要将写文件的内位指针往后退2个字符长度,退到小时之前。

为什么读文件指针退后3个字符长度,而写文件指针退后2个字符指针,它们退后的程度不一样呢?

因为,fgetc()除了读了表征小时的2个字符外还多读入了一个':',而fputc()只写下了表征小时数的两个字符。

读文件指针退到小时之前以后,用文件扫描格式函数fsanf(fp,"%2d:%2d:%2d",&th,&tm,&ts)读出原字幕中的小时、分钟和秒,把这个时间换算成秒,加上时间的差值(也是用秒表示的)。将修正后的时间换算成xx:xx:xx的格式,向新文件中写入即可。

完整代码如下:

#include "stdio.h"
#include "string.h"


main()
{
char originalfullname[1024] = "c:/";//at first,the fullname contains the path;
char changedfullname[1024] = "c:/Changed_";// the name of the new established subtitle file,added prefix;
char inputname[1024] ;//the sheer subtitle file name;
//following is the process that constructs the names of both original and changed;
//just plain concatenation works;
printf("please input the subtitle file name \n");
scanf("%s",inputname);
strcat(originalfullname,inputname);
strcat(changedfullname,inputname);
char *suffix = ".srt";
strcat(originalfullname,suffix);
strcat(changedfullname,suffix);
//
//

int vh,vm,vs;//beginning time of sounding of the special subtitle in video,hour,minute,second,respectively;
printf("input the beginning time of the subtitle in video\n");
printf("in format xx:xx:xx\n");
scanf("%2d:%2d:%2d",&vh,&vm,&vs);
fflush(stdin);

int fh,fm,fs;//beginning of the special subtitle's time in subtitle file,hour,minute,second,respectively;
printf("input the beginning time of the subtitle in subtitle file\n");
printf("in format xx:xx:xx\n");
scanf("%2d:%2d:%2d",&fh,&fm,&fs);

int dt;//difference of time,from subtitle file to video;
dt = ( vh*3600+vm*60+vs) - (fh*3600 + fm*60 + fs);
printf("the time difference is %d\n",dt);

FILE *fp,*fp1;//two file pointers,one is for original subtitle file,while the other for changed subtitle file;
fp = NULL;
fp1 = NULL;

fp = fopen(originalfullname,"r");
fp1 = fopen(changedfullname,"w+");//if no such a file exists,a new file of same name established;
if (!fp || !fp1)//if fp or fp1 is a not effective file pointer,return,ending this program;
    {
    printf("file opening  or file establishing failed!\n ");
    return;
     }

char ch;
int th,tm,ts,time;//time_hour,time_minute,time_second,and time in seconds;
while(   ( ch = fgetc(fp) ) != EOF   )//the idiom,retrieving every character of the file;
    {
    if(ch == ':')
        {
        fseek(fp,-3L,SEEK_CUR);
        fseek(fp1,-2L,SEEK_CUR);
        fscanf(fp,"%2d:%2d:%2d",&th,&tm,&ts);
        time = th*3600 + tm*60 + ts;
        time += dt;
        th = time/3600;
        tm = (time%3600)/60;
        ts = time%60;
        //following,print the time format string.hour ,minute and second apart printed .
        //indeed,they have a entire printing effect as a whole;
        fprintf(fp1,th<=9?"0%d":"%d",th);
        fputc(':',fp1);
        fprintf(fp1,tm<=9?"0%d":"%d",tm);
        fputc(':',fp1);
        fprintf(fp1,ts<=9?"0%d":"%d",ts);
        continue;
           }
      fputc(ch,fp1);
       }
fclose(fp);
}


在找字幕和视频的时间差的时候,先打开字幕文件看一下,看前面几个对话,留下个印象,顺手将字幕文件保存为ANSI编码格式。我听力比较菜,如果之前不留个印象的话,在视频中,光靠听,我是听不清楚一句英语的。然后在视频开头找能听得懂的语句,记录下时间,再到字幕文件中找到对应语句,记录下时间。运行代码的时候,再输入文件名之后,接着输入两个时间,就将字幕中所有语句的时间修改好了。在c盘下找到以Changed开头下划线加上原来文件名的字幕文件。

用暴风影音打开视频,载入修改后的字幕文件,享受纯英语语境下的大片吧。如果有一点点的不匹配,用暴风影音的提前和延迟字幕的功能就好。

当night watch的队长质问john snow胖胖的伙伴tarly:"Did you send the ravens",随着声音响起,匹配的字幕适时出现在视频下方,还是蛮有成就感的!


这虽然只是c语言编程的一个小小的例子。但是它揭示了计算机科学的几个普遍原理:1.一切科学和技术都是为了让人过得更好的,拥有更好的人生体验。2.计算机和编程解决问题的核心,是对问题本身的认识和理解,比如,在这个小实例中,认识到':'是标示时间字符串的关键,后面就势如破竹。同理,在大的计算机解决问题实践中,要花更多的时间去深入理解问题的本身,是关键,也是加力。3.算法的重要性,在这个例子中,我找到冒号以后,将文件指针退到整个时间字符串之前,对整个时间字符串进行扫描,不仅使形式更完备,而且这样就将文件指针推进到整个时间字符串之后,就屏蔽了秒之前那个冒号。否则,还需对两个冒号进行鉴别,哪个是分之前的,哪个是秒之前的,如果读到的是秒之前的冒号怎么办,这样就会复杂很多。
在程序对文件处理的时候,还是需要显示一些提示,这样以降低等待的枯燥。我选择将修改时间的处数打印出来,再加上一些对话语句。


修改了1324处的时间,如果手动修改,真不知道修改到什么时候。计算机科学真是太强大了,我爱死你了,解救人类于重复繁琐枯燥劳动的女神学科!
最终的完整代码如下:

#include "stdio.h"
#include "string.h"

main()
{
char originalfullname[1024] = "c:/";//at first,the fullname contains the path;
char changedfullname[1024] = "c:/Changed_";// the name of the new established subtitle file,added prefix;
char inputname[1024] ;//the sheer subtitle file name;
//following is the process that constructs the names of both original and changed;
//just plain concatenation works;
printf("please input the subtitle file name \n");
scanf("%s",inputname);
strcat(originalfullname,inputname);
strcat(changedfullname,inputname);
char *suffix = ".srt";
strcat(originalfullname,suffix);
strcat(changedfullname,suffix);
//
//

int vh,vm,vs;//beginning  time of sounding of the special subtitle in video,hour,minute,second,respectively;
printf("input the beginning time of the statement in video\n");
printf("in format xx:xx:xx\n");
scanf("%2d:%2d:%2d",&vh,&vm,&vs);
fflush(stdin);

int fh,fm,fs;//the beginning of  subtitle time in subtitle file,hour,minute,second,respectively;
printf("input the beginning time of the subtitle in subtitle file\n");
printf("in format xx:xx:xx\n");
scanf("%2d:%2d:%2d",&fh,&fm,&fs);

int dt;//difference of time,from subtitle file to video;
dt = ( vh*3600+vm*60+vs) - (fh*3600 + fm*60 + fs);
printf("the time difference is %d\n",dt);

FILE *fp,*fp1;//two file pointers,one is for original subtitle file,while the other for modified subtitle file,
                   //which should be newly established.
fp = NULL;
fp1 = NULL;
fp = fopen(originalfullname,"r");
fp1 = fopen(changedfullname,"w+");//if no such a file exists,a new file of same name established;
if (!fp || !fp1)//if fp or fp1 is an ineffective file pointer,return,ending this program;
    {
    printf("file opening  or file establishing failed!\n ");
    return;
     }

char ch;
int th,tm,ts,time;//time_hour,time_minute,time_second,and time in seconds;
int i;
i=0;
while(   ( ch = fgetc(fp) ) != EOF   )//the idiom,retrieving every character of the file;
    {
    if(ch == ':')
        {
        fseek(fp,-3L,SEEK_CUR);//backward ,in front of the time string in read file;
        fseek(fp1,-2L,SEEK_CUR);//backward,prepared for writing time anew entirely;
        fscanf(fp,"%2d:%2d:%2d",&th,&tm,&ts);//get the hour ,minute and second of the original time
        time = th*3600 + tm*60 + ts;
        time += dt;//renew the time ,by plus the  difference;
       //convert the time, for the format , hour:minute:second;
        th = time/3600;
        tm = (time%3600)/60;
        ts = time%60;
        //following,print the time format string.hour ,minute and second apart printed .
        //indeed,they have a entire printing effect as a whole;
        fprintf(fp1,th<=9?"0%d":"%d",th);//if the value less than 10,in form : 0value,for example,7 is 07;
        fputc(':',fp1);
        fprintf(fp1,tm<=9?"0%d":"%d",tm);
        fputc(':',fp1);
        fprintf(fp1,ts<=9?"0%d":"%d",ts);
        i += 1;
        printf("your little program has changed %d ",i);
        printf(i>1?"places":"place");
        printf(" of time\n");
        continue;
           }
      fputc(ch,fp1);
       }
fclose(fp);
fclose(fp1);
printf("enjoy your films!my lady or sir!\n");
getchar();
}	

为了方便没有装c语言编辑器的同学,我把我编译过的应用程序changesubtime.exe上传到我的新浪微盘了。下载地址 下载地址

下载之后,根据以下步骤就可以批量修改字幕时间了。

1.将字幕文件拷到c盘(不要放在任何文件夹里面)。

2.运行changesubtime.exe应用程序,根据提示输入文件名。

3.打开电影,找到一条字幕,记下它的开始时间。在程序中输入,注意格式是两个数字间隔冒号的。

4.打开字幕文件,记事本方式,找到那条字幕,记录字幕的开始时间。保存,关闭记事本。在程序中输入刚才记录的时间。

5.在c盘中找到修改过的字幕文件,以Changed开头,下划线后带的是原来的文件名。将它和电影关联起来。

享受纯英文环境下的视觉大片吧。




  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值