Skip to content

Commit 0bb6ea4

Browse files
jagdish-15kahgoh
andauthored
Sync SGF-Parsing (#2902)
Co-authored-by: Kah Goh <[email protected]>
1 parent 6488e34 commit 0bb6ea4

File tree

4 files changed

+196
-29
lines changed

4 files changed

+196
-29
lines changed

exercises/practice/sgf-parsing/.meta/config.json

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
"authors": [
33
"tlphat"
44
],
5+
"contributors": [
6+
"jagdish-15",
7+
"kahgoh"
8+
],
59
"files": {
610
"solution": [
711
"src/main/java/SgfParsing.java"

exercises/practice/sgf-parsing/.meta/src/reference/java/SgfParsing.java

+51-26
Original file line numberDiff line numberDiff line change
@@ -29,26 +29,52 @@ private int parseFromIndex(String input, int index, SgfNode root) throws SgfPars
2929
StringBuilder buffer = new StringBuilder();
3030
Map<String, List<String>> properties = new HashMap<>();
3131
String key = null;
32+
boolean escape = false;
33+
boolean inValue = false;
3234
while (index < input.length()) {
33-
switch (input.charAt(index)) {
34-
case '(':
35-
index = addNewChild(input, index, root);
36-
break;
37-
case ')':
38-
break;
39-
case '[':
40-
key = loadKeyFromBuffer(buffer, properties);
41-
break;
42-
case ']':
43-
properties.get(key).add(popStringFromBuffer(buffer));
44-
if (input.charAt(index + 1) == ')') {
45-
root.setProperties(properties);
46-
return index + 1;
47-
}
48-
index = examineNextNode(input, index, root, properties);
49-
break;
50-
default:
51-
index = appendCharToBuffer(input, index, buffer);
35+
char nextChar = input.charAt(index);
36+
if (escape) {
37+
if (nextChar != '\n') {
38+
appendChar(buffer, nextChar);
39+
}
40+
escape = false;
41+
} else {
42+
switch (nextChar) {
43+
case '(':
44+
if (inValue) {
45+
buffer.append(nextChar);
46+
} else {
47+
index = addNewChild(input, index, root);
48+
}
49+
break;
50+
case ')':
51+
if (inValue) {
52+
buffer.append(nextChar);
53+
}
54+
break;
55+
case '[':
56+
if (inValue) {
57+
buffer.append(nextChar);
58+
} else {
59+
key = loadKeyFromBuffer(buffer, properties);
60+
inValue = true;
61+
}
62+
break;
63+
case ']':
64+
properties.get(key).add(popStringFromBuffer(buffer));
65+
if (input.charAt(index + 1) == ')') {
66+
root.setProperties(properties);
67+
return index + 1;
68+
}
69+
index = examineNextNode(input, index, root, properties);
70+
inValue = false;
71+
break;
72+
case '\\':
73+
escape = true;
74+
break;
75+
default:
76+
appendChar(buffer, nextChar);
77+
}
5278
}
5379
++index;
5480
}
@@ -101,14 +127,13 @@ private int examineNextNode(String input, int index, SgfNode root, Map<String, L
101127
}
102128
return index;
103129
}
104-
105-
private int appendCharToBuffer(String input, int index, StringBuilder buffer) {
106-
char character = input.charAt(index);
107-
while (character == '\\') {
108-
character = input.charAt(++index);
130+
131+
private void appendChar(StringBuilder builder, char charToAdd) {
132+
if (charToAdd != '\n' && Character.isWhitespace(charToAdd)) {
133+
builder.append(" ");
134+
} else {
135+
builder.append(charToAdd);
109136
}
110-
buffer.append(character);
111-
return index;
112137
}
113138

114139
private void checkIfThereAreDelimiters(StringBuilder buffer) throws SgfParsingException {

exercises/practice/sgf-parsing/.meta/tests.toml

+35
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,40 @@ description = "two child trees"
4545
[724eeda6-00db-41b1-8aa9-4d5238ca0130]
4646
description = "multiple property values"
4747

48+
[28092c06-275f-4b9f-a6be-95663e69d4db]
49+
description = "within property values, whitespace characters such as tab are converted to spaces"
50+
51+
[deaecb9d-b6df-4658-aa92-dcd70f4d472a]
52+
description = "within property values, newlines remain as newlines"
53+
54+
[8e4c970e-42d7-440e-bfef-5d7a296868ef]
55+
description = "escaped closing bracket within property value becomes just a closing bracket"
56+
57+
[cf371fa8-ba4a-45ec-82fb-38668edcb15f]
58+
description = "escaped backslash in property value becomes just a backslash"
59+
60+
[dc13ca67-fac0-4b65-b3fe-c584d6a2c523]
61+
description = "opening bracket within property value doesn't need to be escaped"
62+
63+
[a780b97e-8dbb-474e-8f7e-4031902190e8]
64+
description = "semicolon in property value doesn't need to be escaped"
65+
66+
[0b57a79e-8d89-49e5-82b6-2eaaa6b88ed7]
67+
description = "parentheses in property value don't need to be escaped"
68+
69+
[c72a33af-9e04-4cc5-9890-1b92262813ac]
70+
description = "escaped tab in property value is converted to space"
71+
72+
[3a1023d2-7484-4498-8d73-3666bb386e81]
73+
description = "escaped newline in property value is converted to nothing at all"
74+
75+
[25abf1a4-5205-46f1-8c72-53273b94d009]
76+
description = "escaped t and n in property value are just letters, not whitespace"
77+
78+
[08e4b8ba-bb07-4431-a3d9-b1f4cdea6dab]
79+
description = "mixing various kinds of whitespace and escaped characters in property value"
80+
reimplements = "11c36323-93fc-495d-bb23-c88ee5844b8c"
81+
4882
[11c36323-93fc-495d-bb23-c88ee5844b8c]
4983
description = "escaped property"
84+
include = false

exercises/practice/sgf-parsing/src/test/java/SgfParsingTest.java

+106-3
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,114 @@ public void multiplePropertyValues() throws SgfParsingException {
121121

122122
@Test
123123
@Disabled("Remove to run test")
124-
public void escapedProperty() throws SgfParsingException {
125-
String input = "(;A[\\]b\nc\nd\t\te \n\\]])";
126-
SgfNode expected = new SgfNode(Map.of("A", List.of("]b\nc\nd\t\te \n]")));
124+
public void withinPropertyValueWhitespace() throws SgfParsingException {
125+
String input = "(;A[hello\t\tworld])";
126+
SgfNode expected = new SgfNode(Map.of("A", List.of("hello world")));
127127
SgfNode actual = new SgfParsing().parse(input);
128128
assertThat(actual).isEqualTo(expected);
129129
}
130130

131+
@Test
132+
@Disabled("Remove to run test")
133+
public void withinPropertyValueNewline() throws SgfParsingException {
134+
String input = "(;A[hello\n\nworld])";
135+
SgfNode expected = new SgfNode(Map.of("A", List.of("hello\n\nworld")));
136+
SgfNode actual = new SgfParsing().parse(input);
137+
assertThat(actual).isEqualTo(expected);
138+
}
139+
140+
@Test
141+
@Disabled("Remove to run test")
142+
public void escapedClosingBracket() throws SgfParsingException {
143+
String input = "(;A[\\]])";
144+
SgfNode expected = new SgfNode(Map.of("A", List.of("]")));
145+
SgfNode actual = new SgfParsing().parse(input);
146+
assertThat(actual).isEqualTo(expected);
147+
}
148+
149+
@Test
150+
@Disabled("Remove to run test")
151+
public void escapedBacklash() throws SgfParsingException {
152+
String input = "(;A[\\\\])";
153+
SgfNode expected = new SgfNode(Map.of("A", List.of("\\")));
154+
SgfNode actual = new SgfParsing().parse(input);
155+
assertThat(actual).isEqualTo(expected);
156+
}
157+
158+
@Test
159+
@Disabled("Remove to run test")
160+
public void openingBracketNeedNotToBeEscaped() throws SgfParsingException {
161+
String input = "(;A[x[y\\]z][foo]B[bar];C[baz])";
162+
SgfNode expected = new SgfNode(Map.of("A", List.of("x[y]z", "foo"),
163+
"B", List.of("bar")),
164+
List.of(
165+
new SgfNode(Map.of("C", List.of("baz")))
166+
));
167+
SgfNode actual = new SgfParsing().parse(input);
168+
assertThat(actual).isEqualTo(expected);
169+
}
170+
171+
@Test
172+
@Disabled("Remove to run test")
173+
public void semicolonNeedNotToBeEscaped() throws SgfParsingException {
174+
String input = "(;A[a;b][foo]B[bar];C[baz])";
175+
SgfNode expected = new SgfNode(Map.of("A", List.of("a;b", "foo"),
176+
"B", List.of("bar")),
177+
List.of(
178+
new SgfNode(Map.of("C", List.of("baz")))
179+
));
180+
SgfNode actual = new SgfParsing().parse(input);
181+
assertThat(actual).isEqualTo(expected);
182+
}
183+
184+
@Test
185+
@Disabled("Remove to run test")
186+
public void paranthesesNeedNotToBeEscaped() throws SgfParsingException {
187+
String input = "(;A[x(y)z][foo]B[bar];C[baz])";
188+
SgfNode expected = new SgfNode(Map.of("A", List.of("x(y)z", "foo"),
189+
"B", List.of("bar")),
190+
List.of(
191+
new SgfNode(Map.of("C", List.of("baz")))
192+
));
193+
SgfNode actual = new SgfParsing().parse(input);
194+
assertThat(actual).isEqualTo(expected);
195+
}
196+
197+
@Test
198+
@Disabled("Remove to run test")
199+
public void escapedTab() throws SgfParsingException {
200+
String input = "(;A[hello\\\tworld])";
201+
SgfNode expected = new SgfNode(Map.of("A", List.of("hello world")));
202+
SgfNode actual = new SgfParsing().parse(input);
203+
assertThat(actual).isEqualTo(expected);
204+
}
205+
206+
@Test
207+
@Disabled("Remove to run test")
208+
public void escapedNewline() throws SgfParsingException {
209+
String input = "(;A[hello\\\nworld])";
210+
SgfNode expected = new SgfNode(Map.of("A", List.of("helloworld")));
211+
SgfNode actual = new SgfParsing().parse(input);
212+
assertThat(actual).isEqualTo(expected);
213+
}
214+
215+
216+
@Test
217+
@Disabled("Remove to run test")
218+
public void escapedTAndN() throws SgfParsingException {
219+
String input = "(;A[\\t = t and \\n = n])";
220+
SgfNode expected = new SgfNode(Map.of("A", List.of("t = t and n = n")));
221+
SgfNode actual = new SgfParsing().parse(input);
222+
assertThat(actual).isEqualTo(expected);
223+
}
224+
225+
226+
@Test
227+
@Disabled("Remove to run test")
228+
public void mixOfEscapedCharactersAndWhitespaces() throws SgfParsingException {
229+
String input = "(;A[\\]b\nc\\\nd\t\te\\\\ \\\n\\]])";
230+
SgfNode expected = new SgfNode(Map.of("A", List.of("]b\ncd e\\ ]")));
231+
SgfNode actual = new SgfParsing().parse(input);
232+
assertThat(actual).isEqualTo(expected);
233+
}
131234
}

0 commit comments

Comments
 (0)