Some checks failed
Fast Reverse Tests / test (push) Successful in 1m32s
Markup Tests / test (push) Successful in 17s
Reverse Tests / test (push) Successful in 25s
Sum Tests / test (push) Successful in 27s
Word Stat Tests / test (push) Successful in 25s
Word Stat++ Tests / test (push) Failing after 37s
147 lines
4.5 KiB
Java
147 lines
4.5 KiB
Java
package md2html;
|
|
|
|
import java.io.*;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.*;
|
|
|
|
public class Md2Html {
|
|
|
|
public static void main(String[] args) {
|
|
if (args == null || args.length < 2) {
|
|
return;
|
|
}
|
|
|
|
try (
|
|
BufferedReader reader = new BufferedReader(
|
|
new InputStreamReader(new FileInputStream(args[0]), StandardCharsets.UTF_8));
|
|
BufferedWriter writer = new BufferedWriter(
|
|
new OutputStreamWriter(new FileOutputStream(args[1]), StandardCharsets.UTF_8))
|
|
) {
|
|
List<String> blocks = readBlocks(reader);
|
|
for (String block : blocks) {
|
|
writer.write(convertBlock(block));
|
|
writer.newLine();
|
|
}
|
|
} catch (IOException e) {
|
|
// по условию обычно можно игнорировать или просто завершить
|
|
}
|
|
}
|
|
|
|
private static List<String> readBlocks(BufferedReader reader) throws IOException {
|
|
List<String> blocks = new ArrayList<>();
|
|
StringBuilder current = new StringBuilder();
|
|
String line;
|
|
|
|
while ((line = reader.readLine()) != null) {
|
|
if (line.isEmpty()) {
|
|
if (!current.isEmpty()) {
|
|
blocks.add(current.toString());
|
|
current.setLength(0);
|
|
}
|
|
} else {
|
|
if (!current.isEmpty()) {
|
|
current.append('\n');
|
|
}
|
|
current.append(line);
|
|
}
|
|
}
|
|
|
|
if (!current.isEmpty()) {
|
|
blocks.add(current.toString());
|
|
}
|
|
|
|
return blocks;
|
|
}
|
|
|
|
private static String convertBlock(String block) {
|
|
int level = countHeaderLevel(block);
|
|
|
|
if (level > 0) {
|
|
String content = block.substring(level + 1);
|
|
return "<h" + level + ">" + parseInline(content) + "</h" + level + ">";
|
|
} else {
|
|
return "<p>" + parseInline(block) + "</p>";
|
|
}
|
|
}
|
|
|
|
private static int countHeaderLevel(String block) {
|
|
int i = 0;
|
|
while (i < block.length() && block.charAt(i) == '#') {
|
|
i++;
|
|
}
|
|
if (i > 0 && i <= 6 && i < block.length() && block.charAt(i) == ' ') {
|
|
return i;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private static String parseInline(String text) {
|
|
StringBuilder result = new StringBuilder();
|
|
Deque<String> stack = new ArrayDeque<>();
|
|
|
|
Map<String, String> tags = Map.of(
|
|
"*", "em",
|
|
"_", "em",
|
|
"**", "strong",
|
|
"__", "strong",
|
|
"--", "s",
|
|
"`", "code"
|
|
);
|
|
|
|
for (int i = 0; i < text.length(); ) {
|
|
|
|
// escape
|
|
if (text.charAt(i) == '\\' && i + 1 < text.length()) {
|
|
result.append(escapeHtml(text.charAt(i + 1)));
|
|
i += 2;
|
|
continue;
|
|
}
|
|
|
|
// check double markers first
|
|
if (i + 1 < text.length()) {
|
|
String two = text.substring(i, i + 2);
|
|
if (tags.containsKey(two)) {
|
|
if (!stack.isEmpty() && stack.peek().equals(two)) {
|
|
result.append("</").append(tags.get(two)).append(">");
|
|
stack.pop();
|
|
} else {
|
|
result.append("<").append(tags.get(two)).append(">");
|
|
stack.push(two);
|
|
}
|
|
i += 2;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// single markers
|
|
String one = String.valueOf(text.charAt(i));
|
|
if (tags.containsKey(one)) {
|
|
if (!stack.isEmpty() && stack.peek().equals(one)) {
|
|
result.append("</").append(tags.get(one)).append(">");
|
|
stack.pop();
|
|
} else {
|
|
result.append("<").append(tags.get(one)).append(">");
|
|
stack.push(one);
|
|
}
|
|
i++;
|
|
continue;
|
|
}
|
|
|
|
// normal char
|
|
result.append(escapeHtml(text.charAt(i)));
|
|
i++;
|
|
}
|
|
|
|
return result.toString();
|
|
}
|
|
|
|
private static String escapeHtml(char c) {
|
|
return switch (c) {
|
|
case '<' -> "<";
|
|
case '>' -> ">";
|
|
case '&' -> "&";
|
|
default -> String.valueOf(c);
|
|
};
|
|
}
|
|
}
|