我已经为此工作了大约3个小时,根本无法弄清楚世界上有什么不对。我试图写一个简单的"差异"算法,给定两个字节数组,输出一个单字节数组,描述两者之间的差异。我设法写了一个相当简单的算法,但是围绕字节有一些奇怪的行为" 35"和" 36。"我确定我的代码中某处有一些错误,但我一遍又一遍地仔细检查它,而且我自己也找不到它。因此,我将我的代码提交给大众,希望能够发现我不断错过的任何错误。
该代码旨在接受两个输入a
和b
并生成一些输出c
,这样可以重建a
给定b
和{{} 1}}以及给定c
和b
的{{1}}的重建。对于更多情况,这是我目前未能尝试解决PPGC上的this挑战。
我尝试做的是使用通用格式a
汇编字节数组
字节数组也可以压缩,但我已经验证了它的工作情况。我还验证了索引已正确读取,测试用例已正确加载,并且eof和分隔符正常工作。
守则:
c
其他细节:
在重建<<index><<a-byte><b-byte>...><separator>...><eof-indicator><0 if b, 1 if b><remaining bytes of a or b>
时,算法始终用package com.gmail.socraticphoenix.sandbox;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
public class Diffs {
public static final byte ESCAPE = 1;
public static final byte SEPARATOR = 2;
public static final byte EOF = 3;
public static void main(String[] args) throws IOException {
int totalLength = 0;
System.out.println("Reading files...");
Map<byte[], byte[]> tests = Diffs.getTests();
System.out.println("Finished reading, beginning diff generation.");
for (Map.Entry<byte[], byte[]> pair : tests.entrySet()) {
byte[] a = pair.getKey();
byte[] b = pair.getValue();
byte[] diff = Diffs.generateDiff(a, b);
totalLength += diff.length;
byte[] reconA = Diffs.reverseA(b, diff);
byte[] reconB = Diffs.reverseB(a, diff);
boolean succesful = true;
if (!Arrays.equals(a, reconA)) {
System.out.println("Failed to reconstruct a.");
for (int i = 0; i < Math.min(a.length, reconA.length); i++) {
System.out.print(a[i]);
if (a[i] != reconA[i]) {
System.out.print("^");
} else {
System.out.print(" ");
}
}
System.out.println();
for (int i = 0; i < Math.min(a.length, reconA.length); i++) {
System.out.print(reconA[i]);
if (a[i] != reconA[i]) {
System.out.print("^");
} else {
System.out.print(" ");
}
}
if (a.length != reconA.length) {
System.out.println();
System.out.print("Different lengths");
}
System.out.println();
System.out.println();
succesful = false;
}
if (!Arrays.equals(b, reconB)) {
System.out.println("Failed to reconstruct b.");
for (int i = 0; i < Math.min(b.length, reconB.length); i++) {
System.out.print(b[i]);
if (b[i] != reconB[i]) {
System.out.print("^");
} else {
System.out.print(" ");
}
}
System.out.println();
for (int i = 0; i < Math.min(b.length, reconB.length); i++) {
System.out.print(reconB[i]);
if (b[i] != reconB[i]) {
System.out.print("^");
} else {
System.out.print(" ");
}
}
if (b.length != reconB.length) {
System.out.println();
System.out.print("Different lengths");
}
System.out.println();
System.out.println();
succesful = false;
}
if (!succesful) {
break;
}
}
System.out.println("Finished diff generation.");
System.out.println("Final Length: " + totalLength);
}
public static byte[] generateDiff(byte[] a, byte[] b) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
DataOutputStream dataOut = new DataOutputStream(out);
boolean cp = false;
ByteArrayOutputStream outc = new ByteArrayOutputStream();
int i;
for (i = 0; i < Math.min(a.length, b.length); i++) {
byte ab = a[i];
byte bb = b[i];
if (ab != bb) {
outc.write(ab);
outc.write(bb);
cp = true;
} else {
if (cp) {
byte[] result = outc.toByteArray();
outc = new ByteArrayOutputStream();
dataOut.writeInt(i);
for (byte z : result) {
if (z == Diffs.SEPARATOR || z == Diffs.ESCAPE || z == Diffs.EOF) {
dataOut.write(Diffs.ESCAPE);
}
dataOut.write(z);
}
dataOut.write(Diffs.SEPARATOR);
}
cp = false;
}
}
byte[] result = outc.toByteArray();
outc = new ByteArrayOutputStream();
if (result.length != 0) {
dataOut.writeInt(i);
for (byte z : result) {
if (z == Diffs.SEPARATOR || z == Diffs.ESCAPE || z == Diffs.EOF) {
dataOut.write(Diffs.ESCAPE);
}
dataOut.write(z);
}
dataOut.write(Diffs.SEPARATOR);
}
byte[] remaining;
dataOut.write(Diffs.EOF);
if (a.length < b.length) {
dataOut.write(0);
remaining = b;
} else if (b.length < a.length) {
dataOut.write(1);
remaining = a;
} else {
remaining = new byte[0];
}
for (byte g : remaining) {
dataOut.write(g);
}
dataOut.flush();
byte[] finalResult = out.toByteArray();
byte[] compressed = Diffs.compress(finalResult);
if (compressed.length < finalResult.length) {
outc.write(1);
outc.write(compressed);
} else {
outc.write(0);
outc.write(finalResult);
}
return outc.toByteArray();
}
public static byte[] reverseA(byte[] arrayB, byte[] diff) throws IOException {
byte compressed = diff[0];
byte[] actualDiff = new byte[diff.length - 1];
System.arraycopy(diff, 1, actualDiff, 0, diff.length - 1);
if (compressed == 1) {
actualDiff = Diffs.decompress(actualDiff);
}
DataInputStream in = new DataInputStream(new ByteArrayInputStream(actualDiff));
ByteArrayOutputStream out = new ByteArrayOutputStream();
int current = 0;
while (true) {
in.mark(70);
byte a = in.readByte();
if (a == Diffs.EOF) {
break;
}
in.reset();
Map.Entry<Integer, byte[]> entry = Diffs.fetchNextChunk(in);
int index = entry.getKey();
byte[] vals = entry.getValue();
int i;
for (i = 0; i < index; i++) {
if (current + i < arrayB.length) {
out.write(arrayB[current + i]);
} else {
break;
}
}
current += i + (vals.length / 2);
for (int j = 0; j < vals.length; j++) {
if (j % 2 != 0) {
out.write(vals[j]);
}
}
}
int decider = in.read();
if (decider == 1) {
int i;
while ((i = in.read()) > -1) {
out.write(i);
}
}
return out.toByteArray();
}
public static byte[] reverseB(byte[] arrayA, byte[] diff) throws IOException {
byte compressed = diff[0];
byte[] actualDiff = new byte[diff.length - 1];
System.arraycopy(diff, 1, actualDiff, 0, diff.length - 1);
if (compressed == 1) {
actualDiff = Diffs.decompress(actualDiff);
}
DataInputStream in = new DataInputStream(new ByteArrayInputStream(actualDiff));
ByteArrayOutputStream out = new ByteArrayOutputStream();
int current = 0;
while (true) {
in.mark(70);
byte a = in.readByte();
if (a == Diffs.EOF) {
break;
}
in.reset();
Map.Entry<Integer, byte[]> entry = Diffs.fetchNextChunk(in);
int index = entry.getKey();
byte[] vals = entry.getValue();
int i;
for (i = 0; i < index; i++) {
if (current + i < arrayA.length) {
out.write(arrayA[current + i]);
} else {
break;
}
}
current += i + (vals.length / 2);
for (int j = 0; j < vals.length; j++) {
if (j % 2 == 0) {
out.write(vals[j]);
}
}
}
int decider = in.read();
if (decider == 0) {
int i;
while ((i = in.read()) > -1) {
out.write(i);
}
}
return out.toByteArray();
}
public static Map.Entry<Integer, byte[]> fetchNextChunk(DataInputStream stream) throws IOException {
int i = stream.readInt();
ByteArrayOutputStream out = new ByteArrayOutputStream();
boolean escape = false;
int z;
while ((z = stream.readByte()) > -1) {
if (z == Diffs.ESCAPE && !escape) {
escape = true;
} else {
if (escape) {
out.write(z);
} else {
if (z == Diffs.SEPARATOR) {
break;
}
}
escape = false;
}
}
return new AbstractMap.SimpleEntry<>(i, out.toByteArray());
}
public static byte[] compress(byte[] bytes) throws IOException {
ByteArrayOutputStream stream = new ByteArrayOutputStream(bytes.length);
GZIPOutputStream gzipOutputStream = new GZIPOutputStream(stream);
gzipOutputStream.write(bytes);
gzipOutputStream.close();
stream.close();
return stream.toByteArray();
}
public static byte[] decompress(byte[] bytes) throws IOException {
ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
GZIPInputStream gzipInputStream = new GZIPInputStream(stream);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
int res = 0;
byte[] buf = new byte[1024];
while (res >= 0) {
res = gzipInputStream.read(buf, 0, buf.length);
if (res > 0) {
outputStream.write(buf, 0, res);
}
}
stream.close();
gzipInputStream.close();
outputStream.close();
return outputStream.toByteArray();
}
public static Map<byte[], byte[]> getTests() throws IOException {
String target = "https://gist.githubusercontent.com/nathanmerrill/125a6e2ae7d9ded3531fedff036cf74b/raw/7a578393826014a788b424fd9558cc14c3f8908e/commits.txt";
URL url = new URL(target);
Map<byte[], byte[]> tests = new HashMap<>();
for (String s : Diffs.readLines(url)) {
String[] pieces = s.split(" ");
tests.put(Diffs.readBytes(new URL(pieces[0])), Diffs.readBytes(new URL(pieces[1])));
}
return tests;
}
public static byte[] readBytes(URL url) throws IOException {
InputStream stream = url.openStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
int i;
while ((i = stream.read()) > -1) {
out.write(i);
}
return out.toByteArray();
}
public static List<String> readLines(URL url) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
List<String> lines = new ArrayList<>();
String line;
while ((line = reader.readLine()) != null) {
lines.add(line);
}
return lines;
}
}
替换序列36 32
,并在重构35 32
时用a
替换序列35 32
更具体地说,上述程序的输出是:
36 32
请注意,更改的字节后面紧跟b
感谢您的帮助!