-
Notifications
You must be signed in to change notification settings - Fork 0
/
AutocorrelationVisual.java
169 lines (144 loc) · 5.14 KB
/
AutocorrelationVisual.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
import java.util.HashMap;
import java.util.Map;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;
public class AutocorrelationVisual extends Application {
private String cipherText;
/*
* Allows for the initialization of an
* Autocorrelation-object without a
* ciphertext.
*/
public AutocorrelationVisual() { }
/*
* Allows for the initialization of an
* Autocorrelation-object with a ciphertext.
*/
public AutocorrelationVisual(String cipherText) {
this.cipherText = cipherText;
}
/*
* Returns object's current ciphertext.
*/
public String getCipherText() {
return this.cipherText;
}
/*
* Sets object's current ciphertext.
*/
public void setCipherText(String text) {
this.cipherText = text;
}
/*
* Preprocess input text to upper case,
* remove punctuation, spacing and
* newlines / carriage returns.
*/
public void normalize() {
this.cipherText = this.cipherText.toUpperCase();
this.cipherText = this.cipherText.replaceAll("[\\p{Punct}\\s]+", "");
}
/*
* Preprocess input text to upper case,
* remove punctuation, spacing and
* newlines / carriage returns,
* and replace characters unique to the
* German language.
*/
public void normalizeGerman() {
this.cipherText = this.cipherText.toUpperCase();
this.cipherText = this.cipherText.replaceAll("[\\p{Punct}\\s]+", "");
this.cipherText = this.cipherText.replace("Ä", "AE");
this.cipherText = this.cipherText.replace("Ö", "OE");
this.cipherText = this.cipherText.replace("Ü", "UE");
this.cipherText = this.cipherText.replace("ß", "SS");
}
/*
* Shifts a copy of ciphertext an
* input number of positions.
*/
public String shiftText(int positions) {
StringBuilder sb = new StringBuilder();
for(int i = 0; i < positions; i++) { sb.append("-"); }
sb.append(this.cipherText.substring(0, this.cipherText.length() - positions));
return sb.toString();
}
/*
* A helper function which iterates over
* and prints all shifts of text.
*/
public void printShifts() {
for(int i = 0; i < this.cipherText.length(); i++) {
System.out.println((i < 10 ? "0" + i : i) + ":\t" + this.shiftText(i));
}
}
/*
* Compares ciphertext and shifted
* text and returns the number of
* matching letters for each index.
*/
public int compareTexts(String shiftedText) {
int matches = 0;
for(int i = 0; i < shiftedText.length(); i++) {
if(this.cipherText.charAt(i) == shiftedText.charAt(i)) { matches++; }
}
return matches;
}
/*
* Returns a map containing the number
* of matching letters between ciphertext and
* each shift of the copy of the ciphertext
* up to a supplied number of shifts.
*/
public Map<Integer, Integer> autocorrelate(int shifts) {
Map<Integer, Integer> matches = new HashMap<>();
int i = 0;
while(i < shifts) {
String st = this.shiftText(i);
int count = this.compareTexts(st);
matches.put(i++, count);
}
matches.remove(0); // remove first key-value pair to avoid skewing graph
return matches;
}
/*
* Displays matches per shift as a line chart.
*/
@Override
public void start(Stage primaryStage) {
AutocorrelationVisual acv = new AutocorrelationVisual(getParameters().getNamed().get("ciphertext"));
Map<Integer, Integer> matches = acv.autocorrelate(Integer.valueOf(getParameters().getNamed().get("shifts")));
NumberAxis xAxis = new NumberAxis("Shifts", 0, 80, 1);
NumberAxis yAxis = new NumberAxis("Matches", 0, 45, 1);
xAxis.setMinorTickVisible(false);
yAxis.setMinorTickVisible(false);
LineChart<Number, Number> lineChart = new LineChart<>(xAxis, yAxis);
lineChart.setTitle("Autocorrelation analysis");
lineChart.setLegendVisible(false);
XYChart.Series<Number, Number> data = new XYChart.Series<>();
for(Map.Entry<Integer, Integer> entry : matches.entrySet()) {
data.getData().add(new XYChart.Data<Number, Number>(entry.getKey(), entry.getValue()));
}
lineChart.getData().add(data);
primaryStage.setScene(new Scene(lineChart, 1500, 1000));
primaryStage.show();
}
/*
* To display the line chart of the analysis
* of a ciphertext via autocorrelation, insert
* the ciphertext in `String ciphertext`and
* the desired number of shits in `int shifts`,
* below.
*/
public static void main(String[] args) {
String ciphertext = ""; // INSERT CIPHERTEXT HERE
int shifts = 0; // INSERT NUMBER OF SHIFTS HERE
launch(AutocorrelationVisual.class,
"--ciphertext=" + ciphertext,
"--shifts=" + shifts);
}
}