字符匹配字符串
标题可能表达的不太准确,需求是这样的:我们对用户语音通过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的最优解应该有更好的方法。有更好的方法希望不吝赐教。