java使用正则表达式,针对自定义分词标签,对中文内容进行词频统计(word count)

业务场景

  • 自己定义分词标签,不使用中文分词工具,自己整理收集添加词语(是为了满足任意词语,如人名等)
  • 分词标签可能会互相包含,例如 ABC, AB ,BC三个标签词,对于输入“ABCD”三个标签都要命中,词频加一
  • 需要统计标签词语的出现频率,按照词频倒序
  • 使用尽可能少的查找次数统计出来
  • 避免内存溢出
  • 考虑匹配的速度和效率

代码实现

  • 使用正则表达式 find group,统计词频
  • 为了处理标签词的包含关系,对标签词语遍历处理,得到多个正则表达式
  • 使用java8一些特性,对list、map排序

import com.alibaba.fastjson.JSON;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 词频统计工具类
 * @author yanyulin
 * @date 2020-3-4 00:39:47
 */
public class WordCountUtil {
    //main方法测试
    public static void main(String[] args) {
        String content = "3月2日上午,市长凌云深入企业、职工宿舍、机场,调研疫情防控和经济社会发展工作。市政府秘书长罗平参加调研。\n" +
                "\n" +
                "在合肥长鑫存储技术有限公司,凌云听工作汇报、问应急预案,详细了解企业疫情防控和复工复产情况。得知公司目前员工返岗率达96%,凌云指出,要进一步健全企业内部防控机制,不断加强生产运营调度,加快推动复工达产,努力完成阶段性和全年目标任务。作为安徽单体投资最大的工业项目,该公司外籍员工众多,对外籍员工返肥,公司采取“提前申报+点对点接返+集中隔离”等措施,确保防控和复工“两不误”。对此,凌云表示肯定。她强调,企业要进一步夯实主体责任,严而又严、细而又细、实而又实地做好各项防控工作,确保员工生命健康安全。要主动做好对接工作,为员工提供温馨服务,同时不断完善医院、学校等配套设施建设,让他们留得下住得好,实现安居乐业。对公司提出需要亟需解决的实际问题,凌云要求相关部门,要下大决心,尽快制定切实可行的方案,全力帮助企业稳产、增产。\n" +
                "\n" +
                "在新桥国际机场,凌云实地查看国内厅、国际厅安全公司进出口体温测量设备使用情况,详细了解旅客体温检测、扫码登记等工作开展情况。她指出,目前,国际进出口公司境外输入是疫情防控工作面临的新挑战。要高度警惕境外人员带来的疫情输入风险,克服麻痹思想、摒弃厌战情绪和侥幸心理,进一步夯实责任,落实管控措施,坚决防止疫情输入扩散。要进一步优化工作流程,全力做好来肥人员体温检测和后续跟进工作,切实守好第一道关口。公安边防、海关、机场等部门要建立联防联控工作机制,不断细化工作任务,以更加扎实细致的作风和务实有力的举措,保障旅客安全有序出行,为全面打赢疫情防控阻击战贡献力量。(赵俊松)";
        String words = "疫情|防控|应急|工作|经济社会|安全|企业|国际进出口|复工|公司|疫情防控|安全公司|复工复产|国际|国际进出口公司";
        wordCount(words,content);
    }

    /**
     * 标签词处理,词频检测
     * @param words 词库词语
     * @param content 需要检测的内容
     * @return Map<String,Integer>
     */
    public static Map<String,Integer> wordCount(String words,String content){
        List<String> wordList = Arrays.asList(words.split("\\|"));
        wordList.sort(Comparator.comparingInt(String::length));
        Map<Integer,String> regexMap = new LinkedHashMap<>();
        for(String word:wordList){
            if(regexMap.size() == 0){
                regexMap.put(0,word);
                continue;
            }
            for(int i=0; i < regexMap.size(); i++){
                String regex = regexMap.get(i);
                Pattern p = Pattern.compile(regex);
                Matcher m = p.matcher(word);
                if(!m.find()){
                    regex += "|" + word;
                    regexMap.put(i,regex);
                    break;
                }else if(i+1 == regexMap.size()){
                    regexMap.put(i+1,word);
                    break;
                }
            }
        }
        return wordCount(regexMap,content);
    }

    /**
     * 词频检测
     * @param regexMap 标签词语正则
     * @param content 需要检测的内容
     * @return Map<String,Integer>
     */
    public static Map<String,Integer> wordCount(Map<Integer,String> regexMap,String content){
        System.out.println("正则表达式列表为:" + JSON.toJSONString(regexMap));
        Map<String,Integer> result = new HashMap<>();
        for(int i=0; i < regexMap.size(); i++){
            String regex = regexMap.get(i);
            result.putAll(hitStatistic(regex,content));
        }
        final Map<String, Integer> sortedByCount = result.entrySet()
                .stream()
                .sorted((Map.Entry.<String, Integer>comparingByValue().reversed()))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
        System.out.println("匹配结果为:" + JSON.toJSONString(sortedByCount));
        return sortedByCount;
    }

    //命中统计

    /**
     * 正则命中词频统计
     * @param regex 正则表达式
     * @param content 需要统计的内容
     * @return Map<String,Integer>
     */
    private static Map<String,Integer> hitStatistic(String regex,String content){
        Pattern p = Pattern.compile(regex);
        Matcher m = p.matcher(content);
        Map<String,Integer> result = new LinkedHashMap<>();
        while (m.find()){
            String target = m.group();
            if(result.containsKey(target)){
                result.put(target,result.get(target) + 1);
            }else {
                result.put(target, 1);
            }
        }
        return result;
    }

}

改进思考

  • 匹配的速度、效率,内存使用情况,还没有进行测试,需进一步压测
  • 可以使用结巴分词等第三方jar包,直接对文章内容分词,词频统计
  • 可以利用已有的开源中文词库,作为自己的原始标签库,再手动添加个性化需要的
  • 本文应对的需求是只统计词频,不考虑词性等要素,才可以直接使用正则表达式处理
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

坚持是一种态度

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值