Mercurial Hosting > luan
changeset 1807:ffa28e2155bb
add line_diff
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Sun, 12 May 2024 15:25:29 -0600 |
parents | 3b7a8f1cc887 |
children | 69623c62aa34 |
files | src/goodjava/util/LineDiff.java src/luan/modules/String.luan src/luan/modules/StringLuan.java |
diffstat | 3 files changed, 102 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/goodjava/util/LineDiff.java Sun May 12 15:25:29 2024 -0600 @@ -0,0 +1,90 @@ +package goodjava.util; + +import java.util.List; +import java.util.ArrayList; +import java.io.BufferedReader; +import java.io.StringReader; +import java.io.IOException; + + +public final class LineDiff { + public static final char DELETE = '<'; + public static final char INSERT = '>'; + + public static class Diff { + public final char operation; + public final int line; + public final String text; + + private Diff(char operation,int line,String text) { + this.operation = operation; + this.line = line; + this.text = text; + } + } + + public static String[] stringToLines(String s) { + List<String> list = new ArrayList<String>(); + BufferedReader br = new BufferedReader(new StringReader(s)); + String line; + try { + while( (line = br.readLine()) != null ) { + list.add(line); + } + } catch(IOException e) { + throw new RuntimeException(e); + } + return list.toArray(new String[list.size()]); + } + + public static List<Diff> diff(String oldStr,String newStr) { + return diff( stringToLines(oldStr), stringToLines(newStr) ); + } + + // https://introcs.cs.princeton.edu/java/23recursion/Diff.java.html + public static List<Diff> diff(String[] oldLines,String[] newLines) { + List<Diff> diffs = new ArrayList<Diff>(); + + int nOld = oldLines.length; + int nNew = newLines.length; + + // opt[iOld][iNew] = length of LCS of x[iOld..nOld] and y[iNew..nNew] + int[][] opt = new int[nOld+1][nNew+1]; + + // compute length of LCS and all subproblems via dynamic programming + for (int iOld = nOld-1; iOld >= 0; iOld--) { + for (int iNew = nNew-1; iNew >= 0; iNew--) { + if (oldLines[iOld].equals(newLines[iNew])) + opt[iOld][iNew] = opt[iOld+1][iNew+1] + 1; + else + opt[iOld][iNew] = Math.max(opt[iOld+1][iNew], opt[iOld][iNew+1]); + } + } + + int iOld = 0, iNew = 0; + while (iOld < nOld && iNew < nNew) { + if (oldLines[iOld].equals(newLines[iNew])) { + iOld++; + iNew++; + } else if (opt[iOld+1][iNew] >= opt[iOld][iNew+1]) { + diffs.add( new Diff( DELETE, iOld+1, oldLines[iOld] ) ); + iOld++; + } else { + diffs.add( new Diff( INSERT, iOld+1, newLines[iNew] ) ); + iNew++; + } + } + + // dump out one remainder of one string if the other is exhausted + while( iOld < nOld ) { + diffs.add( new Diff( DELETE, iOld+1, oldLines[iOld] ) ); + iOld++; + } + while( iNew < nNew ) { + diffs.add( new Diff( INSERT, nOld+1, newLines[iNew] ) ); + iNew++; + } + + return diffs; + } +}
--- a/src/luan/modules/String.luan Thu May 09 20:39:53 2024 -0600 +++ b/src/luan/modules/String.luan Sun May 12 15:25:29 2024 -0600 @@ -12,6 +12,7 @@ String.ends_with = StringLuan.ends_with String.find = StringLuan.find String.format = StringLuan.format +String.line_diff = StringLuan.line_diff String.lower = StringLuan.lower String.regex = Boot.regex String.regex_quote = Pattern.quote
--- a/src/luan/modules/StringLuan.java Thu May 09 20:39:53 2024 -0600 +++ b/src/luan/modules/StringLuan.java Sun May 12 15:25:29 2024 -0600 @@ -2,7 +2,9 @@ import java.security.NoSuchAlgorithmException; import java.util.Arrays; +import java.util.List; import goodjava.util.GoodUtils; +import goodjava.util.LineDiff; import luan.Luan; import luan.LuanTable; import luan.LuanFunction; @@ -156,4 +158,13 @@ return GoodUtils.replace(s,target,replacement); } + public static String line_diff(String oldStr,String newStr) { + List<LineDiff.Diff> diffs = LineDiff.diff(oldStr,newStr); + StringBuilder sb = new StringBuilder(); + for( LineDiff.Diff diff : diffs ) { + sb.append(diff.operation).append(' ').append(diff.line).append(" - ").append(diff.text).append('\n'); + } + return sb.toString(); + } + }