字符匹配字符串

标题可能表达的不太准确,需求是这样的:我们对用户语音通过TensorFlowLite识别,识别结果是26字母中的字母,然后要得到语音句子中哪些单词说对了哪些说错了,比如句子是“I am a ball”识别结果是“i a m b l l”。这样的识别结果应该是I AM BALL是对的 A是错误的。

#pragma mark ==========AVAudioRecorderDelegate==========
- (void) audioRecorderDidFinishRecording:(AVAudioRecorder *)avrecorder successfully:(BOOL)flag{
    NSLog(@"录音完毕。开始识别");
    NSLog(@"当前句子%@",self.sentenceModel.sentence_en);
    //去掉标点符号
    NSString * res = [[TFLiteManager shareManager] recognizeAudioWithPath:[self getRecorderPath] text:self.sentenceModel.sentence_en];
    NSLog(@"识别结果:%@",res);
    [self setupRecognizeRes:res];
    

}

- (void)setupRecognizeRes:(NSString *)res{
    self.recognizeCorrectCount = 0;
    self.totalPhomeCount = 0;
    [self.recognizeRes removeAllObjects];
    //识别结果通过空格分割后的集合
    self.recognizeRes  = [NSMutableArray arrayWithArray:[res componentsSeparatedByString:@" "]];
    

    //lowerString小写文本、为了查询字母在原文本中的位置
    NSString * sentence_en = [self.sentenceModel.sentence_en mutableCopy];
    self.upperString = [[NSMutableAttributedString alloc]initWithString:sentence_en];
    self.lowerString = [[NSMutableAttributedString alloc]initWithString:[sentence_en lowercaseString]];

    //目标文本
    NSString * orgin_text = [self.sentenceModel.sentence_en mutableCopy];
    //删除特殊字符便于后面处理
    orgin_text = [orgin_text stringByReplacingOccurrencesOfString:@"\"" withString:@""];
    orgin_text = [orgin_text stringByReplacingOccurrencesOfString:@"." withString:@""];
    orgin_text = [orgin_text stringByReplacingOccurrencesOfString:@"," withString:@""];
    orgin_text = [orgin_text stringByReplacingOccurrencesOfString:@"!" withString:@""];
    orgin_text = [orgin_text stringByReplacingOccurrencesOfString:@"?" withString:@""];
    //全部变小写
    orgin_text = [orgin_text lowercaseString];
    //先将目标文本根据空格分割
    NSArray * originWords =  [orgin_text componentsSeparatedByString:@" "];
    self.totalPhomeCount = originWords.count;

    for (NSString * sub in originWords) {
        [self isCorrectSub:sub];
    }

    //识别结果处理完毕
    [self updateDownbooks];
    
    BOOL allRecorded = [self checkBookPagesisAllRecorded];
    NSLog(@"是否全录音:%d",allRecorded);
    if (allRecorded) {
        NSLog(@"全录完,上传音频,获取最终得分");
        self.bookModel.recorderIndex = [AppSingle sharedAppSingle].record_id;
        self.bookModel.bookScore = [self getBookScore];
        self.bookModel.time = [YCUtils getTimestampString];
        [[AppSingle sharedAppSingle].recordedBooks addObject:self.bookModel];
        [AppSingle sharedAppSingle].record_id ++ ;
        [SaveCachesFile saveDataList:[AppSingle sharedAppSingle].recordedBooks fileName:RecordedList];
    }
    
}
//计算所有句子的平均分
- (float)getBookScore{
    NSInteger sentenceCount = 0;
    NSInteger sentenceScore = 0;
    for (NSInteger i = 0 ;i < self.bookModel.pages.count ; i++) {
        PageModel * page = self.bookModel.pages[i];
        for (NSInteger j = 0; j < page.sentences.count ; j ++) {
            SentenceModel * sentence = page.sentences[j];
            sentenceScore += sentence.score;
            sentenceCount ++ ;
        }
    }
    float res = (float)sentenceScore/(float)sentenceCount;
    NSLog(@"最终得分:%f",res);
    return res;
}
//更新本地数据
- (void)updateDownbooks{
    float score = (float)self.recognizeCorrectCount/(float)self.totalPhomeCount;
    self.currentSpeakCell.scoreView.score = score;
    //再找到对应的page
    for (PageModel * page in self.bookModel.pages) {
        if ([page.page_id isEqualToString:self.sentenceModel.page_id]) {
            //再找到对应的句子
            for (SentenceModel * sentence  in page.sentences) {
                if ([sentence.sentence_id isEqualToString:self.sentenceModel.sentence_id]) {
                    sentence.attributedString  = (NSMutableAttributedString *)self.currentBookCell.lb.attributedText;
                    sentence.score = score;
                    sentence.hasRecord = YES;
                }
            }
        }
    }
}

/**
 检查是否本书内句子是否全部录音
 全部已录音返回YES;
 */
- (BOOL)checkBookPagesisAllRecorded{
    for (PageModel * page in self.bookModel.pages) {
        for (SentenceModel * sentence in page.sentences) {
            if (sentence.hasRecord  == NO) {
                return NO;
            }
        }
    }
    return YES;
}
- (void)isCorrectSub:(NSString *)sub{
    self.right = 0;
    self.wrong = 0;
    //sub是单词,分割为字母
    for (NSInteger i = 0; i < sub.length; i++) {
        NSString * phomes = [sub substringWithRange:NSMakeRange(i, 1)];
        NSInteger index = [self getIndexWithTemp:phomes];
        if (index == -1) {
            //没有找到对应的,开始进行下一次的遍历
            //字母错误
            self.wrong ++;
        }else{
            //字母正确
            self.right ++;
        }
        //正确与否都降遍历后的删除掉,进行后续遍历
        [self.recognizeRes removeObjectsInRange:NSMakeRange(0, index+1)];
        //单词遍历完成
        if (i == sub.length - 1) {
            //查找单词在文本中的位置
            NSMutableArray *locationArr = [self calculateSubStringCount:self.lowerString.string str:sub];
            //筛选正确位置
            NSInteger  loc = [self getCorrectLoc:locationArr sub:sub];
            if (loc == -1) {
                NSLog(@"loction error");
                return;
            }
            
            float score = (float)self.right/(float)sub.length;
            if (score >= 0.5) {
                self.recognizeCorrectCount ++;
                //变绿色
                [self.upperString addAttribute:NSForegroundColorAttributeName value:greenColor range:NSMakeRange(loc, sub.length)];
            }else{
                //变红色
                [self.upperString addAttribute:NSForegroundColorAttributeName value:redColor range:NSMakeRange(loc, sub.length)];
            }
            self.currentBookCell.lb.attributedText = self.upperString;
        }
    }
}


- (NSInteger)getCorrectLoc:(NSMutableArray *)locationArr sub:(NSString *)sub{
    //筛选正确的location  比如this is 中匹配 is。mom o
    for (NSInteger i = 0; i < locationArr.count; i ++) {
        NSInteger  loc = [locationArr[i] integerValue];
        if (loc == 0) {
            return 0;
        }else{
            //前一位必须是空格
            NSMutableAttributedString * fontLocString =(NSMutableAttributedString *)[self.lowerString attributedSubstringFromRange:NSMakeRange(loc - 1, 1)];
            //字符匹配
            NSMutableAttributedString * other_sub = (NSMutableAttributedString *)[self.lowerString attributedSubstringFromRange:NSMakeRange(loc , sub.length)];
            //后一位不能是字母
            NSMutableAttributedString * afterLocString = (NSMutableAttributedString *)[self.lowerString attributedSubstringFromRange:NSMakeRange(loc + sub.length, 1)];
            //同时满足这三个情况才是正确的loc
            if ([@" " isEqualToString:fontLocString.string] && [sub isEqualToString:other_sub.string] && ![self inputIsPhome:afterLocString.string]) {
                return loc;
            }
        }
    }
    return  -1;
}
//判断字符是否是26个字母中的一个
- (BOOL)inputIsPhome:(NSString *)input{
    for (NSString * sub in self.phomes) {
        if ([input isEqualToString:sub]) {
            return YES;
        }
    }
    return NO;
}
/**
 查找子字符串在父字符串中的所有位置
 @param content 父字符串
 @param tab 子字符串
 @return 返回位置数组
 */
- (NSMutableArray*)calculateSubStringCount:(NSString *)content str:(NSString *)tab {
    int location = 0;
    NSMutableArray *locationArr = [NSMutableArray new];
    NSRange range = [content rangeOfString:tab];
    if (range.location == NSNotFound){
        return locationArr;
    }
    //声明一个临时字符串,记录截取之后的字符串
    NSString * subStr = content;
    while (range.location != NSNotFound) {
        if (location == 0) {
            location += range.location;
        } else {
            location += range.location + tab.length;
        }
        //记录位置
        NSNumber *number = [NSNumber numberWithUnsignedInteger:location];
        [locationArr addObject:number];
        //每次记录之后,把找到的字串截取掉
        subStr = [subStr substringFromIndex:range.location + range.length];
//        NSLog(@"subStr %@",subStr);
        range = [subStr rangeOfString:tab];
//        NSLog(@"rang %@",NSStringFromRange(range));
    }
    return locationArr;
}

- (NSInteger )getIndexWithTemp:(NSString *)temp{
    NSInteger index;
    for (NSInteger i = 0; i < self.recognizeRes.count; i ++) {
        NSString *index_str = self.recognizeRes[i];
        if ([index_str isEqualToString:temp]) {
            index = i;
            return index;
        }
    }
    //如果都没有匹配到返回-1
    index = - 1;
    return index;
}

  核心代码是isCorrectSub。注释挺多的,有疑问可以评论。

那个获取location的最优解应该有更好的方法。有更好的方法希望不吝赐教。

posted @ 2019-10-31 14:31  小师傅啊小师傅  阅读(231)  评论(0编辑  收藏  举报