You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android语音识别:连字符、复合词等单词匹配问题的解决方案

语音识别与原文单词匹配解决方案

问题场景与需求

在Android中实现语音识别功能:将固定文本显示在TextView中,把文本按空格分割为单词列表;通过onPartialResult获取逐步返回的语音输入(比如先返回[I],再返回[I am]),每次取语音输入的最后一个单词,与文本中的单词按顺序匹配,匹配成功后用Spannable给对应单词着色,同时维护全局索引跟踪匹配进度。要求Spannable文本必须与TextView原文完全一致,不能修改原文。

遇到的匹配问题

  • 文本中带连字符的单词(如here-there),语音识别会拆成here、there两个独立单词,无法匹配;
  • 文本中的复合词(如carefree),语音识别拆成care、free,难以匹配;
  • 文本中的所有格单词(如day's),语音识别返回days,当前用替换处理,需要更优方案;
  • 有没有不用修改语音识别结果或原文的匹配算法/工具库?手动处理各类问题效率低还影响识别速度。

当前使用代码

private void applyColor(String param){
    ArrayList<String> params = paraToArray(param);
    // from string only get last word
    String newWord = params.get(params.size()-1);
    // get current word of paragraph by using global index tracking 
    String currentWord_FromParagraph = paragraphWords.get(indexHistory);

    // handle 's words
    if(currentWord_FromParagraph.contains("'s")){
        String rootWord = currentWord_FromParagraph.replaceAll("'s\\b", "");
        newWord = rootWord+"'s";
    }
    
    // index of word on paragraph
    int start = paragraph.indexOf(newWord, indexHistoryChar);
    int end = newWord.length();
    
    // match
    if(start != -1 && newWord.equalsIgnoreCase(currentWord_FromParagraph) ){
        // spannable contains paragraph and its global 
         spannableString.setSpan(new ForegroundColorSpan(Color.GREEN), start, 
         start+end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
        // global index for array of words of paragraph. after matching ignore current index so we look for next word
        indexHistory++;
        // similar as above but it is for paragraph character index
        indexHistoryChar = start+end;

        spannableString.setSpan(new ForegroundColorSpan(Color.WHITE), startNext, endNext, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
    }

    txtv_paragraph.setText(spannableString);
}

解决方案

1. 连字符/复合词:换字符序列渐进匹配

别再死磕单个单词的匹配了,改成跟踪语音输入的完整字符序列和原文的匹配进度:

  • 全局维护一个currentMatchPos,记录当前在原文中匹配到的字符位置;
  • 每次拿到onPartialResult的完整文本(别只取最后一个单词),把语音文本和原文从currentMatchPos开始的部分都做标准化:去掉空格、连字符,统一转小写;
  • 找语音文本在标准化后原文片段里的最长匹配前缀,然后对着原文里对应的实际字符范围着色;
  • 最后把currentMatchPos更新到匹配结束的位置。

举个例子:原文是here-there,语音先返回here,标准化后都是here,匹配到原文0-3位的here,着色;接着语音返回here there,标准化后是herethere,原文从第4位开始标准化是there,匹配到原文5-9位的there,直接把整个here-there着色就行。

2. 所有格单词:用规则化模糊匹配

别直接改newWord,而是匹配时做规则化对比:

  • 把原文单词和语音单词都转成标准化形式:比如day's转成days,语音返回的days也转成days,对比标准化后的内容;
  • 规则可以扩展:比如去掉所有格的's、统一大小写、忽略特殊符号等;
  • 只要标准化后内容一致,就直接给原文里的day's着色,完全不用改原文或语音结果。

3. 工具库:用编辑距离做模糊匹配

试试用编辑距离(Levenshtein Distance)计算语音内容和原文单词的相似度,设个阈值(比如相似度≥90%)就算匹配成功,不用改任何内容:

  • 自己实现编辑距离计算函数就行,代码量不大;或者用轻量的工具类,比如Apache Commons Lang里的StringUtils.getLevenshteinDistance(注意Android端引入依赖的体积);
  • 遇到复合词拆分的情况,把连续几个语音单词拼接起来,再和原文单词算相似度:比如语音返回care free,拼成carefree后和原文的carefree算,完全匹配就着色整个单词。

4. 优化匹配逻辑:别卡单词索引

当前用indexHistory按单词索引硬匹配,很容易因为语音拆分卡壳。改成基于字符位置的弹性匹配:

  • 每次匹配从currentMatchPos开始,在原文里找和当前语音输入最匹配的字符范围,不是固定找第indexHistory个单词;
  • 比如语音先返回care,匹配到carefree的前4个字符,着色;接着返回care free,直接匹配到整个carefree,着色整个单词,同时更新currentMatchPos到单词结束的位置。

内容的提问来源于stack exchange,提问作者CrackerKSR

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 11:34:50