作页二:个人项目

这个作业属于哪个课程 软件工程2024 - 广东工业大学
这个作业要求在哪里 软件工程2024 - 班级博客
这个作业的目标 开发个人项目,实现论文查重

github

gitcode仓库地址:https://gitcode.com/wdwwdw/3122004405/tree/main

PSP表格

PSP Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 940 1060
· Estimate · 估计这个任务需要多少时间 900 1000
Development 开发 400 450
· Analysis · 需求分析 (包括学习新技术) 50 40
· Design Spec · 生成设计文档 60 60
· Design Review · 设计复审 30 45
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 20 20
· Design · 具体设计 100 50
· Coding · 具体编码 60 75
· Code Review · 代码复审 20 20
· Test · 测试(自我测试,修改代码,提交修改) 30 20
Reporting 报告 100 60
· Test Repor · 测试报告 30 60
· Size Measurement · 计算工作量 30 60
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 60 100
· 合计 940 1060

计算模块接口的设计与实现过程

  • 使用hcaks对中文字符串进行分词,并在pom.xml中添加依赖:

  • 通过取特征向量计算余弦值,来表示相似度。

// 计算向量的模
    public static double calculateMo(Map<String, Integer> wordFreq) {
        double Mo = 0.0;
        for (int freq : wordFreq.values()) {
            Mo += Math.pow(freq, 2);
        }
        return Math.sqrt(Mo);
    }
    // 计算余弦相似度
    public static double calculateSimilarity(Map<String, Integer> freq1, Map<String, Integer> freq2) {
        double dotProduct = 0.0;
        for (String word : freq1.keySet()) {
            if (freq2.containsKey(word)) {
                dotProduct += freq1.get(word) * freq2.get(word);
            }
        }
        double magnitude1 = calculateMo(freq1);
        double magnitude2 = calculateMo(freq2);
        return dotProduct / (magnitude1 * magnitude2);
    }

    // 将文本分词并转换为单词频率字典
    public static Map<String, Integer> getWordFrequency(String text) {
        Map<String, Integer> wordFreq = new HashMap<>();
        List<Term> termList = StandardTokenizer.segment(text);
        for (Term term : termList) {
            String word = term.word;
            wordFreq.put(word, wordFreq.getOrDefault(word, 0) + 1);
        }
        return wordFreq;
    }

接口部分的性能

// 读取文件内容
    public static String readFile(String filePath) throws IOException {
        StringBuilder content = new StringBuilder();
        BufferedReader reader = new BufferedReader(new FileReader(filePath));
        String line;
        while ((line = reader.readLine()) != null) {
            content.append(line).append("\n");
        }
        reader.close();
        return content.toString();
    }

    // 写入文件
    public static void writeTxt(String content,String txtPath) throws IOException {
        File file = new File(txtPath);
        FileWriter fileWriter ;
        try {
            fileWriter = new FileWriter(file, true);
            fileWriter.write(content, 0, content.length());
            fileWriter.write("\r\n");
            // 关闭资源
            fileWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        }
    }
 public static void main(String[] args) {
        if (args.length < 3) {
            System.err.println("请提供正确的文件路径");
            return;
        }
        try {
            // 读取文件内容
            String text1 = readFile(args[0]);
            String text2 = readFile(args[1]);
            String text3 = (args[2]);

            // 获取文本的单词频率字典
            Map<String, Integer> freq1 = getWordFrequency(text1);
            Map<String, Integer> freq2 = getWordFrequency(text2);

            // 计算余弦相似度
            double similarity = calculateSimilarity(freq1, freq2);
            System.out.println(" " + similarity);
            testCalculateRepeatRate();
            // 格式化并写入相似度到文件
            DecimalFormat df = new DecimalFormat("#.####"); // 格式化保留4位小数
            String formattedValue = df.format(similarity); // 格式化double值
            writeTxt(formattedValue,text3);
        } catch (IOException e) {
            System.out.println("文件读入出现错误: " + e.getMessage());
        }
    }
  • 程序的调用逻辑是main()→readFile()→getWordFrequency()→calculateSimilarity()→calculateMo()→readFile()

    可以看出getWordFrequency()函数性能占比最高,因为我是通过hacks对中文字符串进行分词处理,暂时没想到什么优化方法。

计算模块部分单元测试展示

// 单元测试
    public static void testCalculateRepeatRate() {
       String x1="wdw";
       String y1="wdw";
        // 获取文本的单词频率字典
        Map<String, Integer> freq1 = getWordFrequency(x1);
        Map<String, Integer> freq2 = getWordFrequency(y1);

        // 计算余弦相似度
        double similarity = calculateSimilarity(freq1, freq2);
        System.out.println(" " + similarity);

       String x2="篮球是一项团队性体育运动,通常由两支队伍进行比赛。比赛的目标是通过将篮球投进对方的篮筐来得分,同时阻止对方得分。篮球比赛通常在一个长方形的场地上进行,场地中央有一个高悬挂的篮球架。每支队伍由五名球员组成,他们必须运用技巧和战术来传球、运球、投篮和防守。篮球比赛充满了激烈的竞争和快节奏的动作,同时也需要球员之间的默契和团队合作。";
       String y2="篮球起源于19世纪末的美国,在全球范围内拥有广泛的受众和参与者。它不仅是一项具有身体素质要求的运动,还是一种展示个人技艺、智慧和团队精神的机会。篮球运动培养了球员们的协调性、灵活性、速度和耐力。同时,篮球也成为了一种全球化的文化现象,各种篮球比赛和明星球员的出现。";
        freq1 = getWordFrequency(x2);
        freq2 = getWordFrequency(y2);

        similarity = calculateSimilarity(freq1, freq2);
        System.out.println(" " + similarity);

        String x3="广东大学";
        String y3="广东工业大学";
        freq1 = getWordFrequency(x3);
        freq2 = getWordFrequency(y3);

        similarity = calculateSimilarity(freq1, freq2);
        System.out.println(" " + similarity);

        String x4="吃食堂";
        String y4="吃饭堂";
        freq1 = getWordFrequency(x4);
        freq2 = getWordFrequency(y4);

        similarity = calculateSimilarity(freq1, freq2);
        System.out.println(" " + similarity);

        String x5="拿快递去菜鸟驿站";
        String y5="拿快递去蜂巢快递";
        freq1 = getWordFrequency(x5);
        freq2 = getWordFrequency(y5);

        similarity = calculateSimilarity(freq1, freq2);
        System.out.println(" " + similarity);

        String x6="做计算机程序";
        String y6="做电脑程序";
        freq1 = getWordFrequency(x6);
        freq2 = getWordFrequency(y6);

        similarity = calculateSimilarity(freq1, freq2);
        System.out.println(" " + similarity);

        String x7="ACM(Association for Computing Machinery)是一个致力于促进计算机科学教育和研究的国际性学术组织。ACM成立于1947年,至今已经有着悠久的历史,旨在推动计算机科学领域的发展和创新。";
        String y7="ACM举办的国际性程序设计竞赛吸引着全球各地的优秀程序员参与,这项比赛旨在考验选手的编程能力、算法设计和解决问题的能力。参加ACM竞赛不仅可以锻炼个人的编程技能,还能结识志同道合的同好,共同探讨计算机科学领域的前沿话题。";
        freq1 = getWordFrequency(x7);
        freq2 = getWordFrequency(y7);

        similarity = calculateSimilarity(freq1, freq2);
        System.out.println(" " + similarity);

        String x8="ACM程序设计竞赛以其严谨的赛制和高水平的赛题而闻名于世,每年都吸引着无数热爱算法竞赛的青年才俊参与其中。参加ACM竞赛不仅可以提升个人的编程实力,还能学习到各种高效的算法和数据结构,为日后的职业发展奠定坚实的基础。";
        String y8="除了个人能力的提升,ACM竞赛也强调团队合作和交流,参赛队伍需要密切合作,共同攻克难题。这种合作精神和团队协作能力对于未来从事软件开发等领域的工作也大有裨益。";
        freq1 = getWordFrequency(x8);
        freq2 = getWordFrequency(y8);

        similarity = calculateSimilarity(freq1, freq2);
        System.out.println(" " + similarity);

        String x9="ACM程序设计竞赛是一个展示程序员编程技能和算法能力的舞台,参与者们需要在有限的时间内解决一系列复杂的问题。这种比赛形式不仅考验选手的编程水平,还需要他们具备快速思维和团队合作的能力。";
        String y9="ACM竞赛不仅仅是一场角逐荣誉的比赛,更是一个学习和成长的过程。参与者们可以通过与其他优秀程序员的交流,学习到各种新颖的算法和解题思路,不断完善自己的编程技能。";
        freq1 = getWordFrequency(x9);
        freq2 = getWordFrequency(y9);

        similarity = calculateSimilarity(freq1, freq2);
        System.out.println(" " + similarity);

        String x10="ACM(Association for Computing Machinery)竞赛是全球范围内备受瞩目的程序设计竞赛之一,吸引了来自不同国家和地区的顶尖程序员参与。参加ACM竞赛不仅可以挑战个人的极限,还能拓展视野,结识来自世界各地的同行。";
        String y10="ACM竞赛注重创新和探索,鼓励参赛者勇于挑战自己,突破思维定式。这种竞赛氛围激发了无数年轻程序员的潜力,推动着计算机科学领域的进步和发展。";
        freq1 = getWordFrequency(x10);
        freq2 = getWordFrequency(y10);

        similarity = calculateSimilarity(freq1, freq2);
        System.out.println(" " + similarity);
    }

测试结果:

可以看出在文本语言较少的情况下,查重率会偏高。

模块部分异常处理说明


读入异常,则捕获交给java进行oi异常处理。


写入异常,则捕获并停止写入。

posted @ 2024-03-13 21:12  Five_v_five  阅读(32)  评论(0编辑  收藏  举报