在Java中将纯文本转换为HTML文本

21
我有一个Java程序,它将从服务器接收纯文本。这个纯文本可能包含URL。Java库中是否有任何类可以将纯文本转换为HTML文本?或者其他的库?如果没有的话,那么解决方案是什么?

6
根据定义,纯文本无法包含超链接。 - phihag
2
@phihag 我会说这是纯文本:“www.google.com” - atamanroman
1
你应该更精确地定义你的需求。纯文本是什么样子的?你期望的 HTML 输出是什么样子的? - JB Nizet
5
别傻了,这很简单。atamanroman是正确的。如果我在记事本中写并保存http://www.google.com,并将其保存为文本文件,那么它就是纯文本。因为它包含一个超链接,所以我想在JEditorPan中将其呈现为链接。就这样。 - Shaiful
1
为了抵制所有对此帖子进行的负面评价,我点赞支持。如果不是最理想的提问方式,但问题本身是完全合理的 - 我知道这一点,因为我在寻找同样的答案时也来到了这里。问题基本上是:是否有一个公共API可以执行Daniel回答中代码所做的事情。请给提问者一些喘息的机会。 - Rhubarb
显示剩余5条评论
6个回答

34

您需要编写程序对文本进行一些替换。以下是一些提示:

  • 所有换行符都应该转换为"<br>\n"(\n用于更好地输出可读性)。
  • 所有CR应该被删除(谁还使用DOS编码呢)。
  • 所有成对的空格应该被替换为" &nbsp;"
  • 将"<"替换为"&lt;"
  • 将"&"替换为"&amp;"
  • 所有其他字符<128应该保持不变。
  • 所有其他字符>= 128应该写为"&#"+((int)myChar)+";",以使它们在任何编码中都能够读取。
  • 要自动检测您的链接,您可以使用像"http://[^ ]+""www.[^ ]+"这样的正则表达式,并像JB Nizet所说的那样进行转换。在进行所有其他替换之后,将其转换为"<a href=\""+url+"\">"+url+"</a>"

执行此操作的代码类似于:

public static String escape(String s) {
    StringBuilder builder = new StringBuilder();
    boolean previousWasASpace = false;
    for( char c : s.toCharArray() ) {
        if( c == ' ' ) {
            if( previousWasASpace ) {
                builder.append("&nbsp;");
                previousWasASpace = false;
                continue;
            }
            previousWasASpace = true;
        } else {
            previousWasASpace = false;
        }
        switch(c) {
            case '<': builder.append("&lt;"); break;
            case '>': builder.append("&gt;"); break;
            case '&': builder.append("&amp;"); break;
            case '"': builder.append("&quot;"); break;
            case '\n': builder.append("<br>"); break;
            // We need Tab support here, because we print StackTraces as HTML
            case '\t': builder.append("&nbsp; &nbsp; &nbsp;"); break;  
            default:
                if( c < 128 ) {
                    builder.append(c);
                } else {
                    builder.append("&#").append((int)c).append(";");
                }    
        }
    }
    return builder.toString();
}

然而,链接转换尚未添加。如果有人做了,请更新代码。

抱歉,我没有考虑到这个简单的解决方案。状态机是用于反向情况的,即将HTML转换为纯文本,这有点更加困难。 - Daniel
1
如果您在HTML中正确指定编码方式,则可以跳过“编码字符> 128”部分。 - Joachim Sauer
是的,但你也可以不用关心编码。 - Daniel
1
好的答案- 我基本上将它复制粘贴到我的代码中。令人惊讶的是,在像Apache Commons这样的实用程序库中没有公共API可用于此。 - Rhubarb
3
请注意,以上代码中的转义部分可以通过调用escapeHtml4函数来执行- https://commons.apache.org/proper/commons-lang/javadocs/api-3.4/org/apache/commons/lang3/StringEscapeUtils.html#escapeHtml4(java.lang.String)。 - Ken Lin
显示剩余3条评论

11

我使用模式匹配找到了解决方案。这是我的代码 -

String str = "(?i)\\b((?:https?://|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:\'\".,<>?«»“”‘’]))";
Pattern patt = Pattern.compile(str);
Matcher matcher = patt.matcher(plain);
plain = matcher.replaceAll("<a href=\"$1\">$1</a>");

以下是输入和输出结果 -

输入文本为变量plain

some text and then the URL http://www.google.com and then some other text.

输出:

some text and then the URL <a href="http://www.google.com">http://www.google.com</a> and then some other text.

4

刚刚从所有答案中加入代码:

private static String txtToHtml(String s) {
        StringBuilder builder = new StringBuilder();
        boolean previousWasASpace = false;
        for (char c : s.toCharArray()) {
            if (c == ' ') {
                if (previousWasASpace) {
                    builder.append("&nbsp;");
                    previousWasASpace = false;
                    continue;
                }
                previousWasASpace = true;
            } else {
                previousWasASpace = false;
            }
            switch (c) {
                case '<':
                    builder.append("&lt;");
                    break;
                case '>':
                    builder.append("&gt;");
                    break;
                case '&':
                    builder.append("&amp;");
                    break;
                case '"':
                    builder.append("&quot;");
                    break;
                case '\n':
                    builder.append("<br>");
                    break;
                // We need Tab support here, because we print StackTraces as HTML
                case '\t':
                    builder.append("&nbsp; &nbsp; &nbsp;");
                    break;
                default:
                    builder.append(c);

            }
        }
        String converted = builder.toString();
        String str = "(?i)\\b((?:https?://|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/)(?:[^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(?:\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:\'\".,<>?«»“”‘’]))";
        Pattern patt = Pattern.compile(str);
        Matcher matcher = patt.matcher(converted);
        converted = matcher.replaceAll("<a href=\"$1\">$1</a>");
        return converted;
    }

对于像 www.stackoverflow.com 这样的 URL,应该转换为 http://www.stackoverflow.com - Rubens Mariuzzo

4
请使用以下内容
public static String stringToHTMLString(String string) {
    StringBuffer sb = new StringBuffer(string.length());
    // true if last char was blank
    boolean lastWasBlankChar = false;
    int len = string.length();
    char c;

    for (int i = 0; i < len; i++) {
        c = string.charAt(i);
        if (c == ' ') {
            // blank gets extra work,
            // this solves the problem you get if you replace all
            // blanks with &nbsp;, if you do that you loss 
            // word breaking
            if (lastWasBlankChar) {
                lastWasBlankChar = false;
                sb.append("&nbsp;");
            } else {
                lastWasBlankChar = true;
                sb.append(' ');
            }
        } else {
            lastWasBlankChar = false;
            //
            // HTML Special Chars
            if (c == '"')
                sb.append("&quot;");
            else if (c == '&')
                sb.append("&amp;");
            else if (c == '<')
                sb.append("&lt;");
            else if (c == '>')
                sb.append("&gt;");
            else if (c == '\n')
                // Handle Newline
                sb.append("<br/>");
            else {
                int ci = 0xffff & c;
                if (ci < 160)
                    // nothing special only 7 Bit
                    sb.append(c);
                else {
                    // Not 7 Bit use the unicode system
                    sb.append("&#");
                    sb.append(new Integer(ci).toString());
                    sb.append(';');
                }
            }
        }
    }
    return sb.toString();
}

2

我刚刚在Android应用程序中实现了内容的HTML化(请参见https://github.com/andstatus/andstatus/issues/375)。实际的转换只需使用Android系统库中的三行代码即可完成。这样做的好处是在每个后续版本的Android库中使用更好的实现。

private static String htmlifyPlain(String textIn) {
    SpannableString spannable = SpannableString.valueOf(textIn);
    Linkify.addLinks(spannable, Linkify.WEB_URLS);
    return Html.toHtml(spannable);
}

2
如果您的纯文本URL(这与包含超链接不同,正如您在问题中所写),那么将其转换为HTML中的超链接很简单,只需:
String hyperlink = "<a href='" + url + "'>" + url + "</a>";

那不是字符串。那是带有URL的纯文本。一些文本,然后是URL http://www.google.com,然后是一些其他文本。 - Shaiful
实际上,如果你将其渲染为HTML,它将会是一个链接。你应该多读一些关于HTML的资料。 - Tanner
@Tanner - 你的意思是,如果我将JEditorPan的htmltext设置为纯文本,那么所有以http://....开头的字符串都会变成链接吗? - Shaiful
不行。您的JEditorPane需要设置为HTML格式,然后它将呈现任何文本作为HTML。这意味着它将接受和呈现HTML代码,例如<br>、<p>等。如果要显示链接,您需要将URL格式化为链接格式,可以使用JB Nizet提供的格式<a href='url'>text</a>。 - Tanner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接