Java---中文词匹配 正向、逆向和双向最大匹配算法

完成正向、逆向和双向最大匹配算法


import java.io.*;
import java.util.*;

/**
 * 正向最大匹配
 * 逆向最大匹配
 * 双向最大匹配
 */
public class TwoMaxMatch {
    private static final int MAX_LENGTH = 5;
    public static void main(String[] args) {
        //加载字典
        getDictionary();

        String string1 = "结婚的和尚未结婚的";
        System.out.println("正向最大匹配结果:" + leftMax(string1));
        System.out.println("逆向最大匹配结果:" + rightMax(string1));
        System.out.println("双向最大匹配结果:" + twoMax(string1));
        System.out.println("----------------------------------------------------");
        String string2 = "欢迎新老师生前来就餐";
        System.out.println("正向最大匹配结果:" + leftMax(string2));
        System.out.println("逆向最大匹配结果:" + rightMax(string2));
        System.out.println("双向最大匹配结果:" + twoMax(string2));
        System.out.println("----------------------------------------------------");

        String string3 = "项目的研究主题是商品和服务";
        System.out.println("正向最大匹配结果:" + leftMax(string3));
        System.out.println("逆向最大匹配结果:" + rightMax(string3));
        System.out.println("双向最大匹配结果:" + twoMax(string3));
    }
    /**
     * 正向最大匹配
     */
    public static List<String> leftMax(String str) {

        List<String> results = new ArrayList<String>();
        String input = str;

        while (input.length() > 0) {

            String subSeq;
            // 每次取小于或者等于最大字典长度的子串进行匹配
            if (input.length() < MAX_LENGTH)
                subSeq = input;
            else
                subSeq = input.substring(0, MAX_LENGTH);

            while (subSeq.length() > 0) {
                // 如果字典中含有该子串或者子串颗粒度为1,子串匹配成功
                if (dictionary.contains(subSeq) || subSeq.length() == 1) {
                    results.add(subSeq);
                    // 输入中从前向后去掉已经匹配的子串
                    input = input.substring(subSeq.length());
                    break; // 退出循环,进行下一次匹配
                } else {
                    // 去掉匹配字段最后面的一个字
                    subSeq = subSeq.substring(0, subSeq.length() - 1);
                }
            }

        }
        return results;
    }

    /**
     * 逆向最大匹配
     */
    public static List<String> rightMax(String str) {
        // 采用堆栈处理结果,后进先出
        Stack<String> store = new Stack<String>();
        List<String> results = new ArrayList<String>();
        String input = str;

        while (input.length() > 0) {

            String subSeq;
            // 每次取小于或者等于最大字典长度的子串进行匹配
            if (input.length() < MAX_LENGTH)
                subSeq = input;
            else
                subSeq = input.substring(input.length() - MAX_LENGTH);

            while (subSeq.length() > 0) {
                // 如果字典中含有该子串或者子串颗粒度为1,子串匹配成功
                if (dictionary.contains(subSeq) || subSeq.length() == 1) {
                    store.add(subSeq);
                    // 输入中从后向前去掉已经匹配的子串
                    input = input.substring(0, input.length() - subSeq.length());
                    break;
                } else {
                    // 去掉匹配字段最前面的一个字
                    subSeq = subSeq.substring(1);
                }
            }
        }
        // 输出结果
        int size = store.size();
        for (int i = 0; i < size; i++) {
            results.add(store.pop());
        }

        return results;
    }

    /**
     * 双向最大匹配
     */
    public static List<String> twoMax(String str) {
        List<String> leftmax = leftMax(str);
        List<String> rightmax = rightMax(str);

        // 如果分词的数量结果不同,返回长度较小的
        if (leftmax.size() != rightmax.size()) {
            if (leftmax.size() > rightmax.size())
                return rightmax;
            else
                return rightmax;
        }
        // 如果分词的数量结果相同
        else {
            //计算各自的  单字数
            int leftSingle = 0, rightSingle = 0;
            boolean isEqual = true;
            for (int i = 0; i < rightmax.size(); i++) {
                if (!leftmax.get(i).equals(rightmax.get(i))) {
                    isEqual = false;
                }
                //判断是否为 单字
                if (leftmax.get(i).length() == 1)
                    leftSingle++;
                if (rightmax.get(i).length() == 1)
                    rightSingle++;
            }
            // 如果正向、逆向匹配结果完全相等,返回任意结果
            if (isEqual) {
                return leftmax;
                // 否则,返回单字数少的匹配方式
            } else if (leftSingle > rightSingle)
                return rightmax;
            else
                return leftmax;
        }
    }
    /**
     * 载入字典和自定义添加词
     */
    private static Set<String> dictionary;

    // 初始化字典,采用 hashset 存储
    public static void getDictionary() {
        dictionary = new HashSet<String>();
        String dicpath = "D:/ChineseDic.txt";
        String line = null;
        BufferedReader br;
        try {
            // 按照 UTF-8 编码读入文件
            br = new BufferedReader(new InputStreamReader(new FileInputStream(dicpath), "UTF-8"));
            try {
                while (((line = br.readLine()) != null)) {
                    // 按照空格切分
                    String[] str = line.split("\\s+");
                    for (int i = 0; i < str.length; i++) {
                        line = str[i];
                        dictionary.add(line);
                    }

                }
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    // 自定义添加词汇
    public void addWord(String str) {
        dictionary.add(str);
    }
}

在D盘新新建txt文件,ChineseDic.txt,中文词用空格隔开
内容如下:

项目 研究 目的 商品 服务 和服 研究生 结婚 和尚 结婚 尚末 生命 起源 当下 雨天 地面 积水 下雨天 欢迎 老师 生前 就餐 迎新 师生 前来

代码运行效果如下:

正向最大匹配结果:[结婚,, 和尚,, 结婚,]
逆向最大匹配结果:[结婚,, 和尚,, 结婚,]
双向最大匹配结果:[结婚,, 和尚,, 结婚,]
----------------------------------------------------
正向最大匹配结果:[欢迎,, 老师, 生前,, 就餐]
逆向最大匹配结果:[, 迎新,, 师生, 前来, 就餐]
双向最大匹配结果:[欢迎,, 老师, 生前,, 就餐]
----------------------------------------------------
正向最大匹配结果:[项目,, 研究,,,, 商品, 和服,]
逆向最大匹配结果:[, 目的, 研究,,,, 商品,, 服务]
双向最大匹配结果:[项目,, 研究,,,, 商品, 和服,]

进程已结束,退出代码0

参考:
https://blog.csdn.net/qq_41982466/article/details/100009918

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值