Текст вложенного списка маркеров в HTML

У меня есть это: Пример ввода:

* First item
* Second item
    * Subitem 1
        * sub-subitem!
    * Subitem 3
* Third item

Пример вывода:

<ul>
    <li>First item</li>
    <li>Second item
        <ul>
            <li>Subitem 1
                <ul>
                    <li>sub-subitem!</li>
                </ul>
            </li>
            <li>Subitem 3</li>
        </ul>
    </li>
    <li>Third item</li>
</ul>

Я создал класс Java, который отправляет каждую строку String в массив символов, и я обрабатываю каждый символ отдельно. Моя проблема в том, когда закрывать теги. Есть идеи?

Вот мой код:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class TextToHtml {
    StringBuilder itemName = new StringBuilder();
    String sCurrentLine;
    int usingUlTAG=0;

public TextToHtml(){
        BufferedReader br = null; 
        try {
            boolean closeLItag=false;
            br = new BufferedReader(new FileReader("NestedText.txt"));
            System.out.println("<ul>");
            while ((sCurrentLine = br.readLine()) != null) {
                    char[] item = sCurrentLine.toCharArray();
                    for(int i=0; i<item.length;i++){
                            if(item[i]!='*' && item[i]!='\n' && item[i]!='\t'){
                                    itemName.append(item[i]); 
                continue;
            }   
            if(item[i]=='*'){   
                itemName.append("<li>");
                closeLItag=true;
            }
            else if(item[i]=='\t'){ 
                if(item[i+1]=='*'){ 
                    if(usingUlTAG<1)
                    itemName.append("\t<ul>\n\t\t");
                    itemName.append("\t\n\t\t");
                    usingUlTAG= 1;
                    continue;
                }
                if(item[i+1]=='\t'){    
                    itemName.append("\t\t<ul>\n\n\t\t");
                    usingUlTAG=2;
                    continue;
                }
            }
        }
        if(closeLItag){
            itemName.append("</li>\n");
        }

    }       
    System.out.println(itemName+"/ul>");
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        try {
            if (br != null)br.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

public static void main(String[] args) {
    new TextToHtml();   
}
}

3 ответа

Вам придется заглянуть в следующую строку и посмотреть, отличается ли уровень списка от текущего элемента. Затем вы можете добавить или закрыть теги на основе разницы в уровне, если таковые имеются. Вот код, который делает это:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class TextToHtml
{
    StringBuilder itemName = new StringBuilder();
    String sCurrentLine;
    String sNextLine; // A "peek" at what's next to determine if </li> is needed

    public TextToHtml()
    {
        BufferedReader br = null;
        try
        {
            br = new BufferedReader(new FileReader("NestedText.txt"));
            System.out.println("<ul>");
            sNextLine = br.readLine();
            while ((sCurrentLine = sNextLine) != null)
            {
                sNextLine = br.readLine();

                char[] item = sCurrentLine.toCharArray();
                int itemLevel = 0;
                for (int i = 0; i < item.length; i++)
                {
                    if (item[i] != '*' && item[i] != '\n' && item[i] != '\t')
                    {
                        itemName.append(item[i]);
                    }
                    else if (item[i] == '*')
                    {
                        itemName.append("\t<li>");

                        // Trim leading space character
                        if (item[i + 1] == ' ')
                            i++;
                    }
                    else if (item[i] == '\t')
                    {
                        itemLevel++;
                        itemName.append("\t\t");
                    }
                }

                int nextItemLevel = 0;
                if (sNextLine != null)
                {
                    char[] nextItem = sNextLine.toCharArray();
                    for (int i = 0; i < nextItem.length; i++)
                    {
                        if (nextItem[i] == '\t')
                            nextItemLevel++;
                        else
                            break;
                    }
                }
                // Next is the same level; there are no subitems
                if (itemLevel == nextItemLevel)
                    itemName.append("</li>");
                // Next is a deeper level; there are subitems
                else if (itemLevel < nextItemLevel)
                {
                    // In case the next item is more than 1 level deeper
                    for (int i = itemLevel + 1; i <= nextItemLevel; i++)
                    {
                        itemName.append("\n");
                        for (int j = 0; j < i; j++)
                            itemName.append("\t\t");
                        itemName.append("<ul>");

                        // If the next item's level is reached, it will create its own     <li>
                        if (i != nextItemLevel)
                        {
                            itemName.append("\n");
                            for (int j = 0; j < i; j++)
                                itemName.append("\t\t");
                            itemName.append("\t<li>");
                        }
                    }
                }
                // Next is a higher level; there are tags to close
                else // (itemLevel > nextItemLevel)
                {
                    itemName.append("</li>");
                    for (int i = itemLevel - 1; i >= nextItemLevel; i--)
                    {
                        itemName.append("\n");
                        for (int j = 0; j <= i; j++)
                            itemName.append("\t\t");
                        itemName.append("</ul>\n");
                        for (int j = 0; j < i; j++)
                            itemName.append("\t\t");
                        itemName.append("\t</li>");
                    }
                }
                itemName.append("\n");
            }
            System.out.println(itemName + "</ul>");
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                if (br != null)
                    br.close();
            }
            catch (IOException ex)
            {
                ex.printStackTrace();
            }
        }
    }

    public static void main(String[] args)
    {
        new TextToHtml();
    }
}

Обратите внимание, что это будет работать только в том случае, если уровни имеют отступы, а не пробелы.

Если, как предполагает ваш текущий код, все строки элементов списка в исходном тексте используют жесткие вкладки для отступа, тогда все, что вам нужно сделать, это работать с текстом по строке за раз, отслеживая уровень отступа (количество вкладок) предыдущей строки. Этот код не производит хороший отступ в результирующий HTML, но он получает <ul> а также <li> право вложенности, которое все HTML-браузер действительно заботится

import java.io.*;
import java.util.regex.*;

public class Main {
  public static void main(String[] args) throws Exception {
    StringBuilder result = new StringBuilder();
    BufferedReader br = new BufferedReader(new FileReader("NestedText.txt"));
    try {
      int lastIndent = -1; // indent level of last line
      int depth = 0; // number of levels of <ul> we are currently inside
      String line;
      Pattern indentPattern = Pattern.compile("((\\t*)\\* )?(.*)");
      while((line = br.readLine()) != null) {
        Matcher m = indentPattern.matcher(line);
        m.matches(); // guaranteed to be true, but needed to update matcher state

        if(m.group(1) != null) { // this is a new list item
          int thisIndent = m.end(2); // number of leading tabs, may be zero

          // there are three possible cases
          if(thisIndent == lastIndent) {
            // same level as last list item
            result.append("</li>");
          } else if(thisIndent > lastIndent) {
            // starting a child list
            result.append("<ul>");
            depth++;
          } else {
            // returning to parent list
            result.append("</li>");
            depth--;
            result.append("</ul>");
            result.append("</li>");
          }

          result.append("<li>");
          lastIndent = thisIndent;
        } else { // this is a continuation of the previous list item
          result.append(" ");
        }
        // append this line's text (not including the indent and *)
        result.append(m.group(3));
      }

      // run out of items, close any outstanding lists
      while(depth-- > 0) {
        result.append("</li>");
        result.append("</ul>");
      }

      System.out.println(result);
    } finally {
      br.close();
    }
  }
}

Здесь я рассматриваю любую строку, которая не начинается со вкладок и звездочки, как продолжение предыдущего <li>т.е.

* This is a very long list
item that continues over several
  lines
* This is a second item
    * this is a child item
  that also continues
   over several lines

все в порядке.

Я решил проблему, следуя совету Яна Дворака. следующий код работает, и я помещу ниже в случае, если это помогает кому-то еще. Спасибо за ваш вклад

MarkdownProcessor m = new MarkdownProcessor(); 
String html = null;
try {
html = m.markdown(MyString));
} catch (IOException e) {
e.printStackTrace();
} 
System.out.println(html);
Другие вопросы по тегам