diff --git a/.gitignore b/.gitignore index 78a450f..fb9285f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ *.xml -java/out/ +java/out/* *.iml *.idea* -*out* diff --git a/java/markup/Strikeout.java b/java/markup/Strikeout.java new file mode 100644 index 0000000..7c90599 --- /dev/null +++ b/java/markup/Strikeout.java @@ -0,0 +1,24 @@ +package markup; + +import java.util.List; + +public class Strikeout extends AbstractMarkup { + public Strikeout(List elements) { + super(elements); + } + + @Override + public void toMarkdown(StringBuilder sb) { + toMarkdown(sb, "~"); + } + + @Override + public void toHtml(StringBuilder sb) { + toHtml(sb, "s"); + } + + @Override + public void toTex(StringBuilder sb) { + toTex(sb, "\\textst"); + } +} \ No newline at end of file diff --git a/java/md2html/Md2Html.java b/java/md2html/Md2Html.java new file mode 100644 index 0000000..d1e0831 --- /dev/null +++ b/java/md2html/Md2Html.java @@ -0,0 +1,146 @@ +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 blocks = readBlocks(reader); + for (String block : blocks) { + writer.write(convertBlock(block)); + writer.newLine(); + } + } catch (IOException e) { + // по условию обычно можно игнорировать или просто завершить + } + } + + private static List readBlocks(BufferedReader reader) throws IOException { + List 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 "" + parseInline(content) + ""; + } else { + return "

" + parseInline(block) + "

"; + } + } + + 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 stack = new ArrayDeque<>(); + + Map 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(""); + 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(""); + 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); + }; + } +}