trackler 2.2.1.72 → 2.2.1.73
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/trackler/version.rb +1 -1
- data/problem-specifications/exercises/armstrong-numbers/canonical-data.json +70 -0
- data/problem-specifications/exercises/armstrong-numbers/description.md +10 -0
- data/problem-specifications/exercises/armstrong-numbers/metadata.yml +4 -0
- data/problem-specifications/exercises/bob/canonical-data.json +2 -2
- data/problem-specifications/exercises/bob/description.md +2 -0
- data/tracks/c/config.json +41 -41
- data/tracks/common-lisp/exercises/etl/README.md +1 -1
- data/tracks/common-lisp/exercises/isogram/README.md +1 -1
- data/tracks/delphi/config.json +10 -0
- data/tracks/delphi/config/maintainers.json +2 -2
- data/tracks/delphi/exercises/armstrong-numbers/ArmstrongNumbers.dpr +60 -0
- data/tracks/delphi/exercises/armstrong-numbers/README.md +39 -0
- data/tracks/delphi/exercises/armstrong-numbers/uArmstrongNumbersExample.pas +24 -0
- data/tracks/delphi/exercises/armstrong-numbers/uArmstrongNumbersTests.pas +101 -0
- data/tracks/delphi/exercises/bob/README.md +2 -0
- data/tracks/delphi/exercises/bob/uBobExample.pas +12 -3
- data/tracks/delphi/exercises/bob/uBobTests.pas +80 -23
- data/tracks/go/exercises/bob/README.md +2 -0
- data/tracks/go/exercises/bob/cases_test.go +3 -3
- data/tracks/go/exercises/bob/example.go +3 -0
- data/tracks/go/exercises/book-store/cases_test.go +7 -2
- data/tracks/go/exercises/word-count/cases_test.go +6 -1
- data/tracks/groovy/exercises/linked-list/README.md +1 -1
- data/tracks/haskell/.travis.yml +1 -0
- data/tracks/haskell/bin/ensure-readmes-are-updated.sh +40 -0
- data/tracks/haskell/config.json +9 -0
- data/tracks/haskell/exercises/rail-fence-cipher/README.md +119 -0
- data/tracks/haskell/exercises/rail-fence-cipher/examples/success-standard/package.yaml +16 -0
- data/tracks/haskell/exercises/rail-fence-cipher/examples/success-standard/src/RailFenceCipher.hs +12 -0
- data/tracks/haskell/exercises/rail-fence-cipher/package.yaml +20 -0
- data/tracks/haskell/exercises/rail-fence-cipher/src/RailFenceCipher.hs +7 -0
- data/tracks/haskell/exercises/rail-fence-cipher/stack.yaml +1 -0
- data/tracks/haskell/exercises/rail-fence-cipher/test/Tests.hs +60 -0
- data/tracks/java/CONTRIBUTING.md +14 -5
- data/tracks/java/bin/run-journey-test-from-ci.sh +1 -1
- data/tracks/java/config.json +13 -0
- data/tracks/java/exercises/custom-set/.meta/src/reference/java/CustomSet.java +12 -12
- data/tracks/java/exercises/food-chain/.meta/src/reference/java/FoodChain.java +3 -3
- data/tracks/java/exercises/grade-school/.meta/src/reference/java/School.java +7 -7
- data/tracks/java/exercises/hamming/.meta/src/reference/java/Hamming.java +3 -3
- data/tracks/java/exercises/hexadecimal/.meta/src/reference/java/Hexadecimal.java +2 -4
- data/tracks/java/exercises/isogram/.meta/src/reference/java/IsogramChecker.java +2 -2
- data/tracks/java/exercises/largest-series-product/.meta/src/reference/java/LargestSeriesProductCalculator.java +3 -3
- data/tracks/java/exercises/linked-list/.meta/src/reference/java/DoublyLinkedList.java +6 -6
- data/tracks/java/exercises/markdown/.meta/src/reference/java/Markdown.java +96 -0
- data/tracks/java/exercises/markdown/.meta/version +1 -0
- data/tracks/java/exercises/markdown/README.md +30 -0
- data/tracks/java/exercises/markdown/build.gradle +18 -0
- data/tracks/java/exercises/markdown/src/main/java/Markdown.java +83 -0
- data/tracks/java/exercises/markdown/src/test/java/MarkdownTest.java +95 -0
- data/tracks/java/exercises/settings.gradle +1 -0
- data/tracks/javascript/exercises/alphametics/example.js +13 -9
- data/tracks/kotlin/docs/TESTS.md +14 -11
- data/tracks/ocaml/exercises/bob/example.ml +5 -3
- data/tracks/ocaml/exercises/bob/test.ml +3 -4
- data/tracks/ocaml/exercises/word-count/test.ml +3 -0
- data/tracks/ocaml/tools/test-generator/templates/ocaml/bob/test.ml +0 -1
- data/tracks/perl6/config.json +16 -6
- data/tracks/perl6/exercises/bob/Bob.pm6 +1 -1
- data/tracks/perl6/exercises/bob/Example.pm6 +11 -7
- data/tracks/perl6/exercises/bob/README.md +2 -0
- data/tracks/perl6/exercises/bob/bob.t +3 -3
- data/tracks/perl6/exercises/bob/example.yaml +11 -7
- data/tracks/perl6/exercises/clock/clock.t +17 -17
- data/tracks/perl6/exercises/clock/example.yaml +17 -17
- data/tracks/perl6/exercises/roman-numerals/Example.pm6 +17 -0
- data/tracks/perl6/exercises/roman-numerals/RomanNumerals.pm6 +4 -0
- data/tracks/perl6/exercises/roman-numerals/example.yaml +30 -0
- data/tracks/perl6/exercises/roman-numerals/roman-numerals.t +162 -0
- data/tracks/python/exercises/book-store/book_store_test.py +7 -1
- data/tracks/ruby/config.json +11 -0
- data/tracks/ruby/exercises/isbn-verifier/.meta/.version +1 -0
- data/tracks/ruby/exercises/isbn-verifier/.meta/generator/isbn_verifier_case.rb +28 -0
- data/tracks/ruby/exercises/isbn-verifier/.meta/solutions/isbn_verifier.rb +25 -0
- data/tracks/ruby/exercises/isbn-verifier/README.md +73 -0
- data/tracks/ruby/exercises/isbn-verifier/isbn_verifier_test.rb +105 -0
- data/tracks/ruby/exercises/isogram/.meta/generator/isogram_case.rb +3 -3
- data/tracks/ruby/exercises/isogram/isogram_test.rb +18 -18
- data/tracks/rust/README.md +0 -2
- data/tracks/rust/config.json +11 -0
- data/tracks/rust/exercises/diffie-hellman/tests/diffie-hellman.rs +0 -1
- data/tracks/rust/exercises/parallel-letter-frequency/HINTS.md +2 -2
- data/tracks/rust/exercises/parallel-letter-frequency/README.md +2 -2
- data/tracks/rust/exercises/rna-transcription/example.rs +10 -10
- data/tracks/rust/exercises/rna-transcription/tests/rna-transcription.rs +10 -10
- data/tracks/rust/exercises/series/.gitignore +3 -0
- data/tracks/rust/exercises/series/Cargo.toml +5 -0
- data/tracks/rust/exercises/series/README.md +60 -0
- data/tracks/rust/exercises/series/example.rs +13 -0
- data/tracks/rust/exercises/series/src/lib.rs +3 -0
- data/tracks/rust/exercises/series/tests/series.rs +34 -0
- data/tracks/sml/exercises/nth-prime/README.md +1 -1
- data/tracks/vimscript/.travis.yml +3 -0
- data/tracks/vimscript/docs/LEARNING.md +1 -1
- metadata +38 -2
@@ -17,7 +17,7 @@ for file in $modded_files
|
|
17
17
|
do if [[ $file == exercises* ]] || [[ $file == config.json ]]
|
18
18
|
then
|
19
19
|
for file2 in $modded_files
|
20
|
-
do if [[ $file2 == exercises* ]] && [[ $file2 != exercises/settings.gradle ]]
|
20
|
+
do if [[ $file2 == exercises* ]] && [[ $file2 != exercises/settings.gradle ]] && [[ $file2 != exercises/build.gradle ]]
|
21
21
|
then modded_exercise=${file2#exercises/}
|
22
22
|
modded_exercise=${modded_exercise%%/*}
|
23
23
|
if [[ $last_modded_exercise != $modded_exercise ]]
|
data/tracks/java/config.json
CHANGED
@@ -938,6 +938,19 @@
|
|
938
938
|
"unlocked_by": "rotational-cipher",
|
939
939
|
"uuid": "162bebdc-9bf2-43c0-8460-a91f5fc16147"
|
940
940
|
},
|
941
|
+
{
|
942
|
+
"core": false,
|
943
|
+
"difficulty": 7,
|
944
|
+
"slug": "markdown",
|
945
|
+
"topics": [
|
946
|
+
"strings",
|
947
|
+
"conditionals",
|
948
|
+
"pattern_matching",
|
949
|
+
"refactoring"
|
950
|
+
],
|
951
|
+
"unlocked_by": "scrabble-score",
|
952
|
+
"uuid": "cc18f2e5-4e36-47d6-aa60-8ca5ff54019a"
|
953
|
+
},
|
941
954
|
{
|
942
955
|
"core": false,
|
943
956
|
"difficulty": 7,
|
@@ -6,32 +6,32 @@ import java.util.Set;
|
|
6
6
|
import java.util.function.Predicate;
|
7
7
|
import java.util.stream.Collectors;
|
8
8
|
|
9
|
-
|
9
|
+
class CustomSet<T> {
|
10
10
|
|
11
11
|
private Set<T> set;
|
12
12
|
|
13
|
-
|
13
|
+
CustomSet() {
|
14
14
|
this(Collections.emptyList());
|
15
15
|
}
|
16
16
|
|
17
|
-
|
17
|
+
CustomSet(Collection<T> data) {
|
18
18
|
set = new HashSet<>(data.size());
|
19
19
|
this.set.addAll(data);
|
20
20
|
}
|
21
21
|
|
22
|
-
|
22
|
+
boolean isEmpty() {
|
23
23
|
return set.isEmpty();
|
24
24
|
}
|
25
25
|
|
26
|
-
|
26
|
+
boolean contains(T element) {
|
27
27
|
return set.contains(element);
|
28
28
|
}
|
29
29
|
|
30
|
-
|
30
|
+
boolean isSubset(CustomSet<T> anotherSet) {
|
31
31
|
return set.containsAll(anotherSet.set);
|
32
32
|
}
|
33
33
|
|
34
|
-
|
34
|
+
boolean isDisjoint(CustomSet<T> anotherSet) {
|
35
35
|
if (set.isEmpty() || anotherSet.set.isEmpty()) {
|
36
36
|
return true;
|
37
37
|
}
|
@@ -40,15 +40,15 @@ public class CustomSet<T> {
|
|
40
40
|
.count() == 0;
|
41
41
|
}
|
42
42
|
|
43
|
-
|
43
|
+
boolean equals(CustomSet<T> anotherSet) {
|
44
44
|
return set.equals(anotherSet.set);
|
45
45
|
}
|
46
46
|
|
47
|
-
|
47
|
+
boolean add(T element) {
|
48
48
|
return set.add(element);
|
49
49
|
}
|
50
50
|
|
51
|
-
|
51
|
+
CustomSet<T> getIntersection(CustomSet<T> anotherSet) {
|
52
52
|
return new CustomSet<>(
|
53
53
|
set.stream()
|
54
54
|
.filter(anotherSet.set::contains)
|
@@ -56,13 +56,13 @@ public class CustomSet<T> {
|
|
56
56
|
);
|
57
57
|
}
|
58
58
|
|
59
|
-
|
59
|
+
CustomSet<T> getUnion(CustomSet<T> anotherSet) {
|
60
60
|
final Set<T> union = new HashSet<>(set);
|
61
61
|
union.addAll(anotherSet.set);
|
62
62
|
return new CustomSet<>(union);
|
63
63
|
}
|
64
64
|
|
65
|
-
|
65
|
+
CustomSet<T> getDifference(CustomSet<T> anotherSet) {
|
66
66
|
final Predicate<T> predicate = anotherSet::contains;
|
67
67
|
return new CustomSet<>(
|
68
68
|
set.stream()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import java.util.stream.IntStream;
|
2
2
|
|
3
|
-
|
3
|
+
class FoodChain {
|
4
4
|
|
5
5
|
private static final String[] ANIMALS = {
|
6
6
|
"fly",
|
@@ -21,11 +21,11 @@ public class FoodChain {
|
|
21
21
|
"I don't know how she swallowed a cow!"
|
22
22
|
};
|
23
23
|
|
24
|
-
|
24
|
+
String verse(int verse) {
|
25
25
|
return verseBeginning(verse) + verseMiddle(verse) + verseEnding(verse);
|
26
26
|
}
|
27
27
|
|
28
|
-
|
28
|
+
String verses(int startVerse, int endVerse) {
|
29
29
|
|
30
30
|
String[] verses = new String[endVerse - startVerse + 1];
|
31
31
|
|
@@ -1,34 +1,34 @@
|
|
1
1
|
import java.util.*;
|
2
2
|
|
3
|
-
|
3
|
+
class School {
|
4
4
|
|
5
5
|
private final Map<Integer, List<String>> database = new HashMap<>();
|
6
6
|
|
7
|
-
|
7
|
+
int numberOfStudents() {
|
8
8
|
int result = 0;
|
9
|
-
for (List<String> studentsInGrade: database.values()) {
|
9
|
+
for (List<String> studentsInGrade : database.values()) {
|
10
10
|
result += studentsInGrade.size();
|
11
11
|
}
|
12
12
|
return result;
|
13
13
|
}
|
14
14
|
|
15
|
-
|
15
|
+
void add(String student, int grade) {
|
16
16
|
List<String> students = fetchGradeFromDatabase(grade);
|
17
17
|
students.add(student);
|
18
18
|
}
|
19
19
|
|
20
|
-
|
20
|
+
List<String> grade(int grade) {
|
21
21
|
return new ArrayList<>(fetchGradeFromDatabase(grade));
|
22
22
|
}
|
23
23
|
|
24
|
-
|
24
|
+
List<String> fetchGradeFromDatabase(int grade) {
|
25
25
|
if (!database.containsKey(grade)) {
|
26
26
|
database.put(grade, new LinkedList<>());
|
27
27
|
}
|
28
28
|
return database.get(grade);
|
29
29
|
}
|
30
30
|
|
31
|
-
|
31
|
+
Map<Integer, List<String>> studentsByGradeAlphabetical() {
|
32
32
|
Map<Integer, List<String>> sortedStudents = new HashMap<>();
|
33
33
|
for (Integer grade : database.keySet()) {
|
34
34
|
List<String> studentsInGrade = database.get(grade);
|
@@ -1,11 +1,11 @@
|
|
1
|
-
|
1
|
+
class Hamming {
|
2
2
|
private final int hammingDistance;
|
3
3
|
|
4
|
-
|
4
|
+
Hamming(String leftStrand, String rightStrand) {
|
5
5
|
hammingDistance = computeHammingDistance(leftStrand, rightStrand);
|
6
6
|
}
|
7
7
|
|
8
|
-
|
8
|
+
int getHammingDistance() {
|
9
9
|
return hammingDistance;
|
10
10
|
}
|
11
11
|
|
@@ -1,8 +1,8 @@
|
|
1
1
|
import java.util.Arrays;
|
2
2
|
|
3
|
-
|
3
|
+
class Hexadecimal {
|
4
4
|
private static final String HEXES = "0123456789abcdef";
|
5
|
-
|
5
|
+
static int toDecimal(String input){
|
6
6
|
boolean isHex = input.matches("^[0-9a-f]+");
|
7
7
|
if (!isHex) return 0;
|
8
8
|
return Arrays.stream(input.split(""))
|
@@ -11,5 +11,3 @@ public class Hexadecimal {
|
|
11
11
|
|
12
12
|
}
|
13
13
|
}
|
14
|
-
|
15
|
-
|
@@ -4,9 +4,9 @@ import java.util.Set;
|
|
4
4
|
import static java.util.Arrays.stream;
|
5
5
|
import static java.util.stream.Collectors.joining;
|
6
6
|
|
7
|
-
|
7
|
+
class IsogramChecker {
|
8
8
|
|
9
|
-
|
9
|
+
boolean isIsogram(String word) {
|
10
10
|
|
11
11
|
Set<Character> charSet = new HashSet<>();
|
12
12
|
|
@@ -1,13 +1,13 @@
|
|
1
|
-
|
1
|
+
final class LargestSeriesProductCalculator {
|
2
2
|
|
3
3
|
private final String stringToSearch;
|
4
4
|
|
5
|
-
|
5
|
+
LargestSeriesProductCalculator(final String stringToSearch) throws IllegalArgumentException {
|
6
6
|
this.stringToSearch = stringToSearch;
|
7
7
|
validateStringToSearch();
|
8
8
|
}
|
9
9
|
|
10
|
-
|
10
|
+
long calculateLargestProductForSeriesLength(final int seriesLength) throws IllegalArgumentException {
|
11
11
|
if (seriesLength < 0) {
|
12
12
|
throw new IllegalArgumentException("Series length must be non-negative.");
|
13
13
|
} else if (seriesLength == 0) {
|
@@ -1,7 +1,7 @@
|
|
1
|
-
|
1
|
+
final class DoublyLinkedList<T> {
|
2
2
|
private Element<T> head;
|
3
3
|
|
4
|
-
|
4
|
+
void push(T value) {
|
5
5
|
if (head == null) {
|
6
6
|
head = new Element<>(value, null, null);
|
7
7
|
head.next = head;
|
@@ -15,17 +15,17 @@ public final class DoublyLinkedList<T> {
|
|
15
15
|
head.prev = tail;
|
16
16
|
}
|
17
17
|
|
18
|
-
|
18
|
+
T pop() {
|
19
19
|
head = head.prev;
|
20
20
|
return shift();
|
21
21
|
}
|
22
22
|
|
23
|
-
|
23
|
+
void unshift(T value) {
|
24
24
|
push(value);
|
25
25
|
head = head.prev;
|
26
26
|
}
|
27
27
|
|
28
|
-
|
28
|
+
T shift() {
|
29
29
|
T value = head.value;
|
30
30
|
|
31
31
|
Element<T> newHead = head.next;
|
@@ -48,7 +48,7 @@ public final class DoublyLinkedList<T> {
|
|
48
48
|
private Element<T> prev;
|
49
49
|
private Element<T> next;
|
50
50
|
|
51
|
-
|
51
|
+
Element(T value, Element<T> prev, Element<T> next) {
|
52
52
|
this.value = value;
|
53
53
|
this.prev = prev;
|
54
54
|
this.next = next;
|
@@ -0,0 +1,96 @@
|
|
1
|
+
class Markdown {
|
2
|
+
|
3
|
+
String parse(String markdown) {
|
4
|
+
String[] lines = markdown.split("\n");
|
5
|
+
StringBuilder result = new StringBuilder();
|
6
|
+
boolean activeList = false;
|
7
|
+
|
8
|
+
for (int i = 0; i < lines.length; i++) {
|
9
|
+
String lineResult = parseLine(lines[i]);
|
10
|
+
|
11
|
+
if (lineResult.matches("(<li>).*") && !activeList) {
|
12
|
+
activeList = true;
|
13
|
+
result.append("<ul>");
|
14
|
+
result.append(lineResult);
|
15
|
+
} else if (!lineResult.matches("(<li>).*") && activeList) {
|
16
|
+
activeList = false;
|
17
|
+
result.append("</ul>");
|
18
|
+
result.append(lineResult);
|
19
|
+
} else {
|
20
|
+
result.append(lineResult);
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
if (activeList) {
|
25
|
+
result.append("</ul>");
|
26
|
+
}
|
27
|
+
|
28
|
+
return result.toString();
|
29
|
+
}
|
30
|
+
|
31
|
+
private String parseLine(String markdown) {
|
32
|
+
String result = parseHeader(markdown);
|
33
|
+
|
34
|
+
if (result == null) {
|
35
|
+
result = parseListItem(markdown);
|
36
|
+
}
|
37
|
+
|
38
|
+
if (result == null) {
|
39
|
+
result = parseParagraph(markdown);
|
40
|
+
}
|
41
|
+
|
42
|
+
return result;
|
43
|
+
}
|
44
|
+
|
45
|
+
private String parseHeader(String markdown) {
|
46
|
+
int count = 0;
|
47
|
+
|
48
|
+
for (int i = 0; i < markdown.length(); i++) {
|
49
|
+
if (markdown.charAt(i) == '#') {
|
50
|
+
count++;
|
51
|
+
} else {
|
52
|
+
break;
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
if (count == 0) {
|
57
|
+
return null;
|
58
|
+
}
|
59
|
+
|
60
|
+
return wrap(markdown.substring(count + 1), "h" + Integer.toString(count));
|
61
|
+
}
|
62
|
+
|
63
|
+
private String parseListItem(String markdown) {
|
64
|
+
if (markdown.startsWith("*")) {
|
65
|
+
return wrap(parseText(markdown.substring(2)), "li");
|
66
|
+
}
|
67
|
+
|
68
|
+
return null;
|
69
|
+
}
|
70
|
+
|
71
|
+
private String parseParagraph(String markdown) {
|
72
|
+
return wrap(parseText(markdown), "p");
|
73
|
+
}
|
74
|
+
|
75
|
+
private String parseText(String markdown) {
|
76
|
+
return parseUnderscore(parseDoubleUnderscore(markdown));
|
77
|
+
}
|
78
|
+
|
79
|
+
private String parseUnderscore(String markdown) {
|
80
|
+
return parseViaRegex(markdown, "_", "em");
|
81
|
+
}
|
82
|
+
|
83
|
+
private String parseDoubleUnderscore(String markdown) {
|
84
|
+
return parseViaRegex(markdown, "__", "strong");
|
85
|
+
}
|
86
|
+
|
87
|
+
private String parseViaRegex(String markdown, String delimiter, String tag) {
|
88
|
+
String pattern = delimiter + "(.+)" + delimiter;
|
89
|
+
String replacement = wrap("$1", tag);
|
90
|
+
return markdown.replaceAll(pattern, replacement);
|
91
|
+
}
|
92
|
+
|
93
|
+
private String wrap(String text, String tag) {
|
94
|
+
return "<" + tag + ">" + text + "</" + tag + ">";
|
95
|
+
}
|
96
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
1.1.0
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Markdown
|
2
|
+
|
3
|
+
Refactor a Markdown parser.
|
4
|
+
|
5
|
+
The markdown exercise is a refactoring exercise. There is code that parses a
|
6
|
+
given string with [Markdown
|
7
|
+
syntax](https://guides.github.com/features/mastering-markdown/) and returns the
|
8
|
+
associated HTML for that string. Even though this code is confusingly written
|
9
|
+
and hard to follow, somehow it works and all the tests are passing! Your
|
10
|
+
challenge is to re-write this code to make it easier to read and maintain
|
11
|
+
while still making sure that all the tests keep passing.
|
12
|
+
|
13
|
+
It would be helpful if you made notes of what you did in your refactoring in
|
14
|
+
comments so reviewers can see that, but it isn't strictly necessary. The most
|
15
|
+
important thing is to make the code better!
|
16
|
+
|
17
|
+
# Running the tests
|
18
|
+
|
19
|
+
You can run all the tests for an exercise by entering
|
20
|
+
|
21
|
+
```sh
|
22
|
+
$ gradle test
|
23
|
+
```
|
24
|
+
|
25
|
+
in your terminal.
|
26
|
+
|
27
|
+
|
28
|
+
## Submitting Incomplete Solutions
|
29
|
+
|
30
|
+
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
@@ -0,0 +1,18 @@
|
|
1
|
+
apply plugin: "java"
|
2
|
+
apply plugin: "eclipse"
|
3
|
+
apply plugin: "idea"
|
4
|
+
|
5
|
+
repositories {
|
6
|
+
mavenCentral()
|
7
|
+
}
|
8
|
+
|
9
|
+
dependencies {
|
10
|
+
testCompile "junit:junit:4.12"
|
11
|
+
}
|
12
|
+
|
13
|
+
test {
|
14
|
+
testLogging {
|
15
|
+
exceptionFormat = 'full'
|
16
|
+
events = ["passed", "failed", "skipped"]
|
17
|
+
}
|
18
|
+
}
|
@@ -0,0 +1,83 @@
|
|
1
|
+
class Markdown {
|
2
|
+
|
3
|
+
String parse(String markdown) {
|
4
|
+
|
5
|
+
String[] lines = markdown.split("\n");
|
6
|
+
|
7
|
+
String result = "";
|
8
|
+
|
9
|
+
boolean activeList = false;
|
10
|
+
|
11
|
+
for (int i = 0; i < lines.length; i++) {
|
12
|
+
|
13
|
+
String theLine = parseHeader(lines[i]);
|
14
|
+
|
15
|
+
if (theLine == null) {
|
16
|
+
theLine = parseListItem(lines[i]);
|
17
|
+
}
|
18
|
+
|
19
|
+
if (theLine == null)
|
20
|
+
{
|
21
|
+
theLine = parseParagraph(lines[i]);
|
22
|
+
}
|
23
|
+
|
24
|
+
if (theLine.matches("(<li>).*") && !theLine.matches("(<h).*") && !theLine.matches("(<p>).*") && !activeList) {
|
25
|
+
activeList = true;
|
26
|
+
result = result + "<ul>";
|
27
|
+
result = result + theLine;
|
28
|
+
}
|
29
|
+
|
30
|
+
else if (!theLine.matches("(<li>).*") && activeList) {
|
31
|
+
activeList = false;
|
32
|
+
result = result + "</ul>";
|
33
|
+
result = result + theLine;
|
34
|
+
} else {
|
35
|
+
result = result + theLine;
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
if (activeList) {
|
40
|
+
result = result + "</ul>";
|
41
|
+
}
|
42
|
+
|
43
|
+
return result;
|
44
|
+
}
|
45
|
+
|
46
|
+
private String parseHeader(String markdown) {
|
47
|
+
int count = 0;
|
48
|
+
|
49
|
+
for (int i = 0; i < markdown.length() && markdown.charAt(i) == '#'; i++)
|
50
|
+
{
|
51
|
+
count++;
|
52
|
+
}
|
53
|
+
|
54
|
+
if (count == 0) { return null; }
|
55
|
+
|
56
|
+
return "<h" + Integer.toString(count) + ">" + markdown.substring(count + 1) + "</h" + Integer.toString(count)+ ">";
|
57
|
+
}
|
58
|
+
|
59
|
+
private String parseListItem(String markdown) {
|
60
|
+
if (markdown.startsWith("*")) {
|
61
|
+
String skipAsterisk = markdown.substring(2);
|
62
|
+
String listItemString = parseSomeSymbols(skipAsterisk);
|
63
|
+
return "<li>" + listItemString + "</li>";
|
64
|
+
}
|
65
|
+
|
66
|
+
return null;
|
67
|
+
}
|
68
|
+
|
69
|
+
private String parseParagraph(String markdown) {
|
70
|
+
return "<p>" + parseSomeSymbols(markdown) + "</p>";
|
71
|
+
}
|
72
|
+
|
73
|
+
private String parseSomeSymbols(String markdown) {
|
74
|
+
|
75
|
+
String lookingFor = "__(.+)__";
|
76
|
+
String update = "<strong>$1</strong>";
|
77
|
+
String workingOn = markdown.replaceAll(lookingFor, update);
|
78
|
+
|
79
|
+
lookingFor = "_(.+)_";
|
80
|
+
update = "<em>$1</em>";
|
81
|
+
return workingOn.replaceAll(lookingFor, update);
|
82
|
+
}
|
83
|
+
}
|