Mercurial Hosting > luan
comparison src/goodjava/util/LineDiff.java @ 1807:ffa28e2155bb
add line_diff
| author | Franklin Schmidt <fschmidt@gmail.com> |
|---|---|
| date | Sun, 12 May 2024 15:25:29 -0600 |
| parents | |
| children | 69623c62aa34 |
comparison
equal
deleted
inserted
replaced
| 1806:3b7a8f1cc887 | 1807:ffa28e2155bb |
|---|---|
| 1 package goodjava.util; | |
| 2 | |
| 3 import java.util.List; | |
| 4 import java.util.ArrayList; | |
| 5 import java.io.BufferedReader; | |
| 6 import java.io.StringReader; | |
| 7 import java.io.IOException; | |
| 8 | |
| 9 | |
| 10 public final class LineDiff { | |
| 11 public static final char DELETE = '<'; | |
| 12 public static final char INSERT = '>'; | |
| 13 | |
| 14 public static class Diff { | |
| 15 public final char operation; | |
| 16 public final int line; | |
| 17 public final String text; | |
| 18 | |
| 19 private Diff(char operation,int line,String text) { | |
| 20 this.operation = operation; | |
| 21 this.line = line; | |
| 22 this.text = text; | |
| 23 } | |
| 24 } | |
| 25 | |
| 26 public static String[] stringToLines(String s) { | |
| 27 List<String> list = new ArrayList<String>(); | |
| 28 BufferedReader br = new BufferedReader(new StringReader(s)); | |
| 29 String line; | |
| 30 try { | |
| 31 while( (line = br.readLine()) != null ) { | |
| 32 list.add(line); | |
| 33 } | |
| 34 } catch(IOException e) { | |
| 35 throw new RuntimeException(e); | |
| 36 } | |
| 37 return list.toArray(new String[list.size()]); | |
| 38 } | |
| 39 | |
| 40 public static List<Diff> diff(String oldStr,String newStr) { | |
| 41 return diff( stringToLines(oldStr), stringToLines(newStr) ); | |
| 42 } | |
| 43 | |
| 44 // https://introcs.cs.princeton.edu/java/23recursion/Diff.java.html | |
| 45 public static List<Diff> diff(String[] oldLines,String[] newLines) { | |
| 46 List<Diff> diffs = new ArrayList<Diff>(); | |
| 47 | |
| 48 int nOld = oldLines.length; | |
| 49 int nNew = newLines.length; | |
| 50 | |
| 51 // opt[iOld][iNew] = length of LCS of x[iOld..nOld] and y[iNew..nNew] | |
| 52 int[][] opt = new int[nOld+1][nNew+1]; | |
| 53 | |
| 54 // compute length of LCS and all subproblems via dynamic programming | |
| 55 for (int iOld = nOld-1; iOld >= 0; iOld--) { | |
| 56 for (int iNew = nNew-1; iNew >= 0; iNew--) { | |
| 57 if (oldLines[iOld].equals(newLines[iNew])) | |
| 58 opt[iOld][iNew] = opt[iOld+1][iNew+1] + 1; | |
| 59 else | |
| 60 opt[iOld][iNew] = Math.max(opt[iOld+1][iNew], opt[iOld][iNew+1]); | |
| 61 } | |
| 62 } | |
| 63 | |
| 64 int iOld = 0, iNew = 0; | |
| 65 while (iOld < nOld && iNew < nNew) { | |
| 66 if (oldLines[iOld].equals(newLines[iNew])) { | |
| 67 iOld++; | |
| 68 iNew++; | |
| 69 } else if (opt[iOld+1][iNew] >= opt[iOld][iNew+1]) { | |
| 70 diffs.add( new Diff( DELETE, iOld+1, oldLines[iOld] ) ); | |
| 71 iOld++; | |
| 72 } else { | |
| 73 diffs.add( new Diff( INSERT, iOld+1, newLines[iNew] ) ); | |
| 74 iNew++; | |
| 75 } | |
| 76 } | |
| 77 | |
| 78 // dump out one remainder of one string if the other is exhausted | |
| 79 while( iOld < nOld ) { | |
| 80 diffs.add( new Diff( DELETE, iOld+1, oldLines[iOld] ) ); | |
| 81 iOld++; | |
| 82 } | |
| 83 while( iNew < nNew ) { | |
| 84 diffs.add( new Diff( INSERT, nOld+1, newLines[iNew] ) ); | |
| 85 iNew++; | |
| 86 } | |
| 87 | |
| 88 return diffs; | |
| 89 } | |
| 90 } |
