3

我有一堆关于 Markdown 格式编程的文本。有一个构建过程能够将这些文本转换为 Word/HTML,还可以执行简单的验证规则,例如拼写检查或检查文档是否具有所需的标题结构。我想扩展该构建代码以检查所有文本中的复制粘贴或类似块。

是否有任何现有的 Java/Groovy 库可以帮助我进行该分析?

我的第一个想法是使用 PMD 的 CopyPasteDetector,但它过于面向分析真实代码。我不知道如何使用它来分析普通文本。

4

3 回答 3

2

你可能想试试Dude,我自己的快速而肮脏的文本文件重复检测器。除了为您提供两个文本文件之间共享多少的快速估计外,它还可以确定一组文件之间的复制,绘制一个很好的共享关系图。

于 2013-07-06T17:13:11.790 回答
2

毕竟我最终使用了 CPD 和 Groovy。如果有人感兴趣,这里是代码:

import net.sourceforge.pmd.cpd.Tokens
import net.sourceforge.pmd.cpd.TokenEntry
import net.sourceforge.pmd.cpd.Tokenizer
import net.sourceforge.pmd.cpd.CPDNullListener
import net.sourceforge.pmd.cpd.MatchAlgorithm
import net.sourceforge.pmd.cpd.SourceCode
import net.sourceforge.pmd.cpd.SourceCode.StringCodeLoader
import net.sourceforge.pmd.cpd.SimpleRenderer

// Prepare empty token data.
TokenEntry.clearImages()
def tokens = new Tokens()

// List all source files with text.
def source = new TreeMap<String, SourceCode>()
new File('.').eachFile { file ->
  if (file.isFile() && file.name.endsWith('.txt')) {
    def analyzedText = file.text
    def sourceCode = new SourceCode(new StringCodeLoader(analyzedText, file.name))
    source.put(sourceCode.fileName, sourceCode)
    analyzedText.eachLine { line, lineNumber ->
      line.split('[\\W\\s\\t\\f]+').each { token ->
        token = token.trim()
        if (token) {
          tokens.add(new TokenEntry(token, sourceCode.fileName, lineNumber + 1))
        }
      }
    }
    tokens.add(TokenEntry.getEOF())
  }
}

// Run matching algorithm.
def maxTokenChain = 15
def matchAlgorithm = new MatchAlgorithm(source, tokens, maxTokenChain, new CPDNullListener())
matchAlgorithm.findMatches()

// Produce report.
matchAlgorithm.matches().each { match ->
  println "  ========================================"
  match.iterator().each { mark ->
    println "  DUPLICATION ERROR: <${mark.tokenSrcID}:${mark.beginLine}> [DUPLICATION] Found a ${match.lineCount} line (${match.tokenCount} tokens) duplication!"
  }
  def indentedTextSlice = ""
  match.sourceCodeSlice.eachLine { line ->
    indentedTextSlice += "  $line\n"
  }
  println "  ----------------------------------------"
  println indentedTextSlice
  println "  ========================================"
}
于 2013-07-15T19:54:21.853 回答
1

您可以从两个字符串的简单实现最长公共子字符串 (LCS)算法开始。请参阅一种Java 实现

接下来,您可以看到Suffix ArraysGenetics and string algorithms

另请参阅大文本中的最长公共子字符串

于 2013-07-06T18:07:49.067 回答