Esempio n. 1
0
  /**
   * Find the differences between two texts. Simplifies the problem by stripping any common prefix
   * or suffix off the texts before diffing.
   *
   * @return List of Difference objects
   */
  public List<Difference> compare() {
    // Check for equality (speedup)
    List<Difference> diffs;
    if (source.equals(target)) {
      diffs = new ArrayList<Difference>();
      diffs.add(new Difference(EditType.EQUAL, source));
      return diffs;
    }

    // Trim off common prefix (speedup)
    int commonLength = Commonality.prefix(source, target);
    String commonPrefix = source.substring(0, commonLength);
    source = source.substring(commonLength);
    target = target.substring(commonLength);

    // Trim off common suffix (speedup)
    commonLength = Commonality.suffix(source, target);
    String commonSuffix = source.substring(source.length() - commonLength);
    source = source.substring(0, source.length() - commonLength);
    target = target.substring(0, target.length() - commonLength);

    // Compute the diff on the middle block
    diffs = compute();

    // Restore the prefix and suffix
    if (!"".equals(commonPrefix)) {
      diffs.add(0, new Difference(EditType.EQUAL, commonPrefix));
    }

    if (!"".equals(commonSuffix)) {
      diffs.add(new Difference(EditType.EQUAL, commonSuffix));
    }

    DiffCleanup.cleanupMerge(diffs);

    return diffs;
  }
Esempio n. 2
0
  /**
   * Find the differences between two texts.
   *
   * @return List of Difference objects
   */
  private List<Difference> compute() {
    List<Difference> diffs = new ArrayList<Difference>();

    if ("".equals(source)) {
      // Just add some text (speedup)
      diffs.add(new Difference(EditType.INSERT, target));
      return diffs;
    }

    if ("".equals(target)) {
      // Just delete some text (speedup)
      diffs.add(new Difference(EditType.DELETE, source));
      return diffs;
    }

    String longText = source.length() > target.length() ? source : target;
    String shortText = source.length() > target.length() ? target : source;
    int i = longText.indexOf(shortText);
    if (i != -1) {
      // Shorter text is inside the longer text (speedup)
      EditType editType = (source.length() > target.length()) ? EditType.DELETE : EditType.INSERT;
      diffs.add(new Difference(editType, longText.substring(0, i)));
      diffs.add(new Difference(EditType.EQUAL, shortText));
      diffs.add(new Difference(editType, longText.substring(i + shortText.length())));
      return diffs;
    }

    // Check to see if the problem can be split in two.
    CommonMiddle middleMatch = Commonality.halfMatch(source, target);
    if (middleMatch != null) {
      // A half-match was found, sort out the return data.
      // Send both pairs off for separate processing.
      Diff startDiff =
          new Diff(middleMatch.getSourcePrefix(), middleMatch.getTargetPrefix(), checkLines);
      Diff endDiff =
          new Diff(middleMatch.getSourceSuffix(), middleMatch.getTargetSuffix(), checkLines);
      // Merge the results.
      diffs = startDiff.compare();
      diffs.add(new Difference(EditType.EQUAL, middleMatch.getCommonality()));
      diffs.addAll(endDiff.compare());
      return diffs;
    }

    // Perform a real diff.
    if (checkLines && source.length() + target.length() < 250) {
      checkLines = false; // Too trivial for the overhead.
    }

    LineMap lineMap = null;
    if (checkLines) {
      // Scan the text on a line-by-line basis first.
      lineMap = new LineMap(source, target);
      source = lineMap.getSourceMap();
      target = lineMap.getTargetMap();
    }

    diffs = new DifferenceEngine(source, target).generate();

    if (diffs == null) {
      // No acceptable result.
      diffs = new ArrayList<Difference>();
      diffs.add(new Difference(EditType.DELETE, source));
      diffs.add(new Difference(EditType.INSERT, target));
    }

    if (checkLines && lineMap != null) {
      // Convert the diff back to original text.
      lineMap.restore(diffs);
      // Eliminate freak matches (e.g. blank lines)
      DiffCleanup.cleanupSemantic(diffs);

      // Rediff any replacement blocks, this time character-by-character.
      // Add a dummy entry at the end.
      diffs.add(new Difference(EditType.EQUAL, ""));
      int countDeletes = 0;
      int countInserts = 0;
      StringBuilder textDelete = new StringBuilder();
      StringBuilder textInsert = new StringBuilder();
      ListIterator<Difference> pointer = diffs.listIterator();
      Difference curDiff = pointer.next();
      while (curDiff != null) {
        EditType editType = curDiff.getEditType();
        if (EditType.INSERT.equals(editType)) {
          countInserts++;
          textInsert.append(curDiff.getText());
        } else if (EditType.DELETE.equals(editType)) {
          countDeletes++;
          textDelete.append(curDiff.getText());
        } else {
          // Upon reaching an equality, check for prior redundancies.
          if (countDeletes >= 1 && countInserts >= 1) {
            // Delete the offending records and add the merged ones.
            pointer.previous();
            for (int j = 0; j < countDeletes + countInserts; j++) {
              pointer.previous();
              pointer.remove();
            }
            Diff newDiff = new Diff(textDelete.toString(), textInsert.toString(), false);
            for (Difference diff : newDiff.compare()) {
              pointer.add(diff);
            }
          }
          countInserts = 0;
          countDeletes = 0;
          textDelete.delete(0, textDelete.length());
          textInsert.delete(0, textInsert.length());
        }
        curDiff = pointer.hasNext() ? pointer.next() : null;
      }
      diffs.remove(diffs.size() - 1); // Remove the dummy entry at the
      // end.
    }
    return diffs;
  }