QRC与LRC合并

之前坑了QRC格式歌词转LRC格式,那么现在是合并QRC与LRC。貌似也没什么好说的了,就是些文本处理。直接上代码吧。

#import <Foundation/Foundation.h>
#import <string>
#import <iostream>
#import <fstream>
#import <regex.h>
 
using namespace std;
 
/*!
 *  @brief      把微秒时间转为LRC中的时间
 *
 *  @discussion 并未考虑超过99:59.99的时间
 *
 *  @return     [dd:dd.dd]
 */
 
const char * microseconds_to_LRC_time(long long microsecond) {
    double seconds = microsecond / 1000.0;
    int min = seconds / 60;
    double sec = seconds - 60 * min;
    return [NSString stringWithFormat:@"%02d:%05.2lf",min,sec].UTF8String;
}
 
@interface QRC : NSObject
 
/*!
 *  @brief  合并QRC与LRC
 *
 *  @param QRCPath QRC文件路径
 *  @param LRCPath LRC文件路径
 *  @param error   出错时返回错误码和原因
 */
+ (void)ParserQRCDoc:(NSString *)QRCPath CombineLRC:(NSString *)LRCPath Error:(NSError **)error;

@end

@implementation QRC

+ (void)ParserQRCDoc:(NSString *)QRCPath CombineLRC:(NSString *)LRCPath Error:(NSError **)error {
    NSMutableArray * array = [NSMutableArray new];

#pragma mark
#pragma mark - Handle QRC

    ifstream QRC_in(QRCPath.UTF8String);
    if(!QRC_in) {
        *error = [[NSError alloc] initWithDomain:@"com.[data deleted].QRC" code:-1 userInfo:@{@"Error":@"No such QRC file"}];
        return;
    }

    string str;
    int cflags = REG_EXTENDED;
    regex_t reg;
    const char * pattern = "^\[([0-9]+)";
    // 匹配以'['开头, 并且后面跟着数字的就行了
    // 因为是转为LRC, 故提取出每句开始的时间就行

    int z = regcomp(&reg, pattern, cflags);
    if (z != 0) {
        char ebuf[128];
        regerror(z, &reg, ebuf, sizeof(ebuf));
        *error = [[NSError alloc] initWithDomain:@"com.[data deleted].QRC" code:-2 userInfo:@{@"Error":[NSString stringWithFormat:@"%s",ebuf]}];
        regfree(&reg);
        return;
    }

    regmatch_t pm[10];
    const size_t nmatch = 10;

    while(getline(QRC_in, str)) {
        z = regexec(&reg, str.c_str(), nmatch, pm, 0);
        if (z == REG_NOMATCH) continue;
        else if (z != 0) {
            char ebuf[128];
            regerror(z, &reg, ebuf, sizeof(ebuf));
            *error = [[NSError alloc] initWithDomain:@"com.[data deleted].QRC" code:-3 userInfo:@{@"Error":[NSString stringWithFormat:@"%s",ebuf]}];
            regfree(&reg);
            return;
        } else {
            const char * line = str.c_str();
            long long microseconds = 0;
            for (int x = 1; x < nmatch && pm[x].rm_so != -1; ++ x) {
                char *mstr = strndup(line + pm[x].rm_so, pm[x].rm_eo-pm[x].rm_so);
                microseconds = atoll(mstr);
                free(mstr);
            }
            BOOL print = YES;
            char * lrc = (char *)malloc(sizeof(char) * 512);
            int index = 0;
            for(int i = 0; i < strlen(line); i++) {
                if (line[i] == '[' || line[i] == '(') {
                    print = NO;
                    continue;
                } else if (line[i] == ']' || line[i] == ')') {
                    print = YES;
                    continue;
                } else {
                    if (print) {
                        lrc[index] = line[i];
                        index++;
                    }
                }
            }
            lrc[index] = '';
            [array addObject:@{@"Time":[[NSString alloc] initWithFormat:@"%lld",microseconds],@"Type":@"QRC",@"LRC":[[NSString alloc] initWithCString:lrc encoding:NSUTF8StringEncoding]}];
            free(lrc);
        }
    }

#pragma mark
#pragma mark - Handle LRC

    ifstream LRC_in(LRCPath.UTF8String);
    if(!LRC_in) {
        *error = [[NSError alloc] initWithDomain:@"com.[data deleted].QRC" code:-4 userInfo:@{@"Error":@"No such LRC file"}];
        return;
    }
    const char * LRC_pattern = "^\[([0-9]+):([0-9]+).([0-9]+)";
    z = regcomp(&reg, LRC_pattern, cflags);
    if (z != 0) {
        char ebuf[128];
        regerror(z, &reg, ebuf, sizeof(ebuf));
        *error = [[NSError alloc] initWithDomain:@"com.[data deleted].QRC" code:-5 userInfo:@{@"Error":[NSString stringWithFormat:@"%s",ebuf]}];
        regfree(&reg);
        return;
    }
    while(getline(LRC_in, str)) {
        z = regexec(&reg, str.c_str(), nmatch, pm, 0);
        if (z == REG_NOMATCH) printf("%sn",str.c_str());
        else if (z != 0) {
            char ebuf[128];
            regerror(z, &reg, ebuf, sizeof(ebuf));
            *error = [[NSError alloc] initWithDomain:@"com.[data deleted].QRC" code:-6 userInfo:@{@"Error":[NSString stringWithFormat:@"%s",ebuf]}];
            regfree(&reg);
            return;
        } else {
            const char * line = str.c_str();
            long long microseconds = 0;
            for (int x = 1; x < nmatch && pm[x].rm_so != -1; ++ x){
                char *mstr = strndup(line + pm[x].rm_so, pm[x].rm_eo-pm[x].rm_so);
                if (x == 1) microseconds += atoll(mstr) * 60 * 1000;
                else if (x == 2) microseconds += atoll(mstr) * 1000;
                else if (x == 3) microseconds += atoll(mstr) * 10;
                free(mstr);
            }
            BOOL print = YES;
            char * lrc = (char *)malloc(sizeof(char) * 512);
            int index = 0;
            for(int i = 0; i < strlen(line); i++){
                if (line[i] == '[' || line[i] == '('){
                    print = NO;
                    continue;
                } else if (line[i] == ']' || line[i] == ')'){
                    print = YES;
                    continue;
                } else{
                    if (print){
                        lrc[index] = line[i];
                        index++;
                    }
                }
            }
            lrc[index] = '';
            NSString * LRC_Content = [[NSString alloc] initWithCString:lrc encoding:NSUTF8StringEncoding];
            if (LRC_Content.length > 0) {
                [array addObject:@{@"Time":[[NSString alloc] initWithFormat:@"%lld", microseconds], @"Type" : @"LRC", @"LRC" : LRC_Content}];
            }
        }
    }

#pragma mark
#pragma mark - Sort LRC & QRC

    [array sortUsingComparator:^NSComparisonResult(NSDictionary * obj1, NSDictionary * obj2) {
        long long t1 = [[obj1 valueForKey:@"Time"] longLongValue];
        long long t2 = [[obj2 valueForKey:@"Time"] longLongValue];
        if (t1 > t2) return NSOrderedDescending;
        else if (t1 == t2) return NSOrderedSame;
        else return NSOrderedAscending;
    }];

#pragma mark
#pragma mark - Combine

    for (int i = 1; i < array.count; i++){
        if (abs([[[array objectAtIndex:i - 1] valueForKey:@"Time"] longLongValue] - [[[array objectAtIndex:i] valueForKey:@"Time"] longLongValue]) < 600) {
            if ([[[array objectAtIndex:i] valueForKey:@"Type"] isEqualToString:@"QRC"]) {
                printf("[%s] %s %sn",microseconds_to_LRC_time([[[array objectAtIndex:i-1] valueForKey:@"Time"] longLongValue]),[(NSString *)[[array objectAtIndex:i-1] valueForKey:@"LRC"] UTF8String],[(NSString *)[[array objectAtIndex:i] valueForKey:@"LRC"] UTF8String]);
            } else {
                printf("[%s] %s %sn",microseconds_to_LRC_time([[[array objectAtIndex:i] valueForKey:@"Time"] longLongValue]),[(NSString *)[[array objectAtIndex:i] valueForKey:@"LRC"] UTF8String],[(NSString *)[[array objectAtIndex:i-1] valueForKey:@"LRC"] UTF8String]);
            }
            i++;
        } else {
            printf("[%s] %sn",microseconds_to_LRC_time([[[array objectAtIndex:i] valueForKey:@"Time"] longLongValue]),[(NSString *)[[array objectAtIndex:i] valueForKey:@"LRC"] UTF8String]);
        }
    }
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool
    {
        int limition = argc;
        if (argc % 2 != 0) {
            limition -= 1;
        }
        for (int i = 1; i < limition; i+=2) {
            NSError *error;
            [QRC ParserQRCDoc:[NSString stringWithUTF8String:argv[i]] CombineLRC:[NSString stringWithUTF8String:argv[i+1]] Error:&error];
        }
    }
    return 0;
}

Leave a Reply

Your email address will not be published. Required fields are marked *

eleven − two =