如何结合正则与Jaro-Winkler/Levenshtein相似度提取含字符误差的PDF文本值?
基于OCR错误修正+相似度匹配的文本提取方案
核心思路
先预处理修正常见OCR字符错误,再结合Jaro-Winkler/Levenshtein相似度定位目标前后缀,最后提取中间值。
步骤1:预处理修正OCR错误
针对OCR常见的字符混淆(如0↔O、I↔l、1↔I、n↔h),通过字符映射表结合上下文判断(比如单词中的0替换为O)做文本清洗,减少正则匹配障碍。
步骤2:相似度匹配定位前后缀
用Jaro-Winkler(适合短文本相似度)或Levenshtein(基于编辑距离)算法,找到与目标前后缀(如some text和some other text)相似度达标(或编辑距离在允许范围内)的片段,确定提取范围。
步骤3:提取并清洗目标值
在定位到的前后缀之间提取内容,再用正则过滤掉多余的分隔符(如空格、逗号、短横线),得到最终目标值。
Java实现示例
需要引入Apache Commons Text库(提供相似度计算工具),Maven依赖:
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-text</artifactId> <version>1.10.0</version> </dependency>
提取代码:
import org.apache.commons.text.similarity.JaroWinklerDistance; import java.util.HashMap; import java.util.Map; public class OcrValueExtractor { // 常见OCR字符错误映射 private static final Map<Character, Character> OCR_ERROR_MAP = new HashMap<>(); static { OCR_ERROR_MAP.put('0', 'O'); OCR_ERROR_MAP.put('l', 'I'); OCR_ERROR_MAP.put('1', 'I'); OCR_ERROR_MAP.put('n', 'h'); // 适配otner→other的错误 } // 预处理文本,修正常见OCR错误 private static String preprocessOcrText(String text) { StringBuilder sb = new StringBuilder(text); for (int i = 0; i < sb.length(); i++) { char c = sb.charAt(i); if (OCR_ERROR_MAP.containsKey(c)) { // 判断是否为单词组成部分,是则替换为对应字母 boolean isInWord = (i > 0 && Character.isLetter(sb.charAt(i-1))) || (i < sb.length()-1 && Character.isLetter(sb.charAt(i+1))); if (isInWord) { sb.setCharAt(i, OCR_ERROR_MAP.get(c)); } } } return sb.toString(); } // 用Jaro-Winkler相似度匹配前后缀,提取中间值 private static String extractTargetValue(String ocrText, String targetPrefix, String targetSuffix, double simThreshold) { JaroWinklerDistance distance = new JaroWinklerDistance(); String processedText = preprocessOcrText(ocrText); // 定位前缀位置 int prefixEnd = -1; int prefixLen = targetPrefix.length(); for (int i = 0; i <= processedText.length() - prefixLen; i++) { String sub = processedText.substring(i, i + prefixLen); if (distance.apply(sub, targetPrefix) >= simThreshold) { prefixEnd = i + prefixLen; break; } } if (prefixEnd == -1) return null; // 定位后缀位置 int suffixStart = -1; int suffixLen = targetSuffix.length(); for (int i = prefixEnd; i <= processedText.length() - suffixLen; i++) { String sub = processedText.substring(i, i + suffixLen); if (distance.apply(sub, targetSuffix) >= simThreshold) { suffixStart = i; break; } } if (suffixStart == -1) return null; // 提取并清洗目标值 String candidate = processedText.substring(prefixEnd, suffixStart).trim(); return candidate.replaceAll("^[ -]*(.*?)[ ,-]*$", "$1"); } public static void main(String[] args) { String ocrText = "s0me text MY_VALUE, some otner text"; String prefix = "some text"; String suffix = "some other text"; String result = extractTargetValue(ocrText, prefix, suffix, 0.8); System.out.println("提取结果:" + result); // 输出 MY_VALUE } }
注意事项
- 阈值调整:根据OCR错误率调整相似度阈值,错误多则设为0.7-0.8,错误少可设为0.9
- 扩展错误映射:根据实际PDF的OCR错误类型,补充更多字符映射(如e↔c、t↔f等)
- 替换相似度算法:如果偏好编辑距离,可改用
LevenshteinDistance,判断编辑距离≤2即可认为匹配
内容的提问来源于stack exchange,提问作者Si7ius
相关产品推荐
相关产品推荐

