从String中删除HTML标记

时间:2008-10-27 16:39:29

标签: java html parsing

有没有一种从Java字符串中删除HTML的好方法?像

这样的简单正则表达式
 replaceAll("\\<.*?>","") 

会起作用,但像&amp;这样的东西不会被正确转换,并且两个尖括号之间的非HTML将被删除(即正则表达式中的.*?将消失)。

33 个答案:

答案 0 :(得分:526)

使用HTML解析器而不是正则表达式。使用Jsoup,这很简单。

public static String html2text(String html) {
    return Jsoup.parse(html).text();
}

Jsoup还supports针对可自定义的白名单删除了HTML标记,如果您只想允许这样做,则非常有用。 <b><i><u>

另见:

答案 1 :(得分:262)

如果您正在为 Android 撰写文章,则可以执行此操作...

android.text.Html.fromHtml(instruction).toString()

答案 2 :(得分:77)

如果用户输入<b>hey!</b>,您要显示<b>hey!</b>还是hey!?如果第一个,逃避少数,和html编码&符号(和可选的引号),你很好。对代码实施第二个选项的修改是:

replaceAll("\\<[^>]*>","")

但如果用户输入格式错误的内容(例如<bhey!</b>

),您将遇到问题

您还可以查看将解析“脏”html输入的JTidy,并为您提供删除标记的方法,并保留文字。

尝试剥离html的问题是浏览器具有非常宽松的解析器,比你能找到的任何库都宽松,所以即使你尽力剥离所有标签(使用上面的替换方法,DOM库,或者JTidy),需要确保编码任何剩余的HTML特殊字符以保证输出的安全。

答案 3 :(得分:28)

另一种方法是使用 javax.swing.text.html.HTMLEditorKit 来提取文本。

import java.io.*;
import javax.swing.text.html.*;
import javax.swing.text.html.parser.*;

public class Html2Text extends HTMLEditorKit.ParserCallback {
    StringBuffer s;

    public Html2Text() {
    }

    public void parse(Reader in) throws IOException {
        s = new StringBuffer();
        ParserDelegator delegator = new ParserDelegator();
        // the third parameter is TRUE to ignore charset directive
        delegator.parse(in, this, Boolean.TRUE);
    }

    public void handleText(char[] text, int pos) {
        s.append(text);
    }

    public String getText() {
        return s.toString();
    }

    public static void main(String[] args) {
        try {
            // the HTML to convert
            FileReader in = new FileReader("java-new.html");
            Html2Text parser = new Html2Text();
            parser.parse(in);
            in.close();
            System.out.println(parser.getText());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

参考:Remove HTML tags from a file to extract only the TEXT

答案 4 :(得分:23)

我认为过滤html标签的最简单方法是:

private static final Pattern REMOVE_TAGS = Pattern.compile("<.+?>");

public static String removeTags(String string) {
    if (string == null || string.length() == 0) {
        return string;
    }

    Matcher m = REMOVE_TAGS.matcher(string);
    return m.replaceAll("");
}

答案 5 :(得分:18)

使用Jericho也很简单,你可以保留一些格式(例如换行符和链接)。

    Source htmlSource = new Source(htmlText);
    Segment htmlSeg = new Segment(htmlSource, 0, htmlSource.length());
    Renderer htmlRend = new Renderer(htmlSeg);
    System.out.println(htmlRend.toString());

答案 6 :(得分:15)

在Android上,试试这个:

String result = Html.fromHtml(html).toString();

答案 7 :(得分:12)

HTML Escaping真的很难做到 - 我肯定建议使用库代码来做到这一点,因为它比你想象的要复杂得多。查看Apache的StringEscapeUtils以获得一个非常好的库,用于在Java中处理它。

答案 8 :(得分:12)

简单地做Jsoup.parse(html).text()的答案有2个潜在问题(使用JSoup 1.7.3):

  • 删除文字中的换行符
  • 它会将文字&lt;script&gt;转换为<script>

如果您使用它来防止XSS,这有点烦人。以下是使用JSoup和Apache StringEscapeUtils的改进解决方案的最佳镜头:

// breaks multi-level of escaping, preventing &amp;lt;script&amp;gt; to be rendered as <script>
String replace = input.replace("&amp;", "");
// decode any encoded html, preventing &lt;script&gt; to be rendered as <script>
String html = StringEscapeUtils.unescapeHtml(replace);
// remove all html tags, but maintain line breaks
String clean = Jsoup.clean(html, "", Whitelist.none(), new Document.OutputSettings().prettyPrint(false));
// decode html again to convert character entities back into text
return StringEscapeUtils.unescapeHtml(clean);

请注意,最后一步是因为我需要将输出用作纯文本。如果您只需要HTML输出,那么您应该能够删除它。

这里有一堆测试用例(输入到输出):

{"regular string", "regular string"},
{"<a href=\"link\">A link</a>", "A link"},
{"<script src=\"http://evil.url.com\"/>", ""},
{"&lt;script&gt;", ""},
{"&amp;lt;script&amp;gt;", "lt;scriptgt;"}, // best effort
{"\" ' > < \n \\ é å à ü and & preserved", "\" ' > < \n \\ é å à ü and & preserved"}

如果您找到更好的方法,请告诉我。

答案 9 :(得分:6)

在剥离HTML之前,您可能希望用换行符替换<br/></p>标记,以防止它成为Tim建议的难以辨认的混乱。

我可以考虑删除HTML标记但将非HTML放在尖括号之间的唯一方法是检查list of HTML tags。这些方面的东西......

replaceAll("\\<[\s]*tag[^>]*>","")

然后对特殊字符进行HTML解码,例如&amp;。结果不应被视为消毒。

答案 10 :(得分:5)

这应该有效 -

使用此

  text.replaceAll('<.*?>' , " ") -> This will replace all the html tags with a space.

和这个

  text.replaceAll('&.*?;' , "")-> this will replace all the tags which starts with "&" and ends with ";" like &nbsp;, &amp;, &gt; etc.

答案 11 :(得分:4)

对于我指出的测试用例,接受的答案对我不起作用:“a&lt; b或b&gt; c”的结果是“a b或b&gt; c”。

所以,我使用了TagSoup。这是一个适用于我的测试用例(和其他几个)的镜头:

import java.io.IOException;
import java.io.StringReader;
import java.util.logging.Logger;

import org.ccil.cowan.tagsoup.Parser;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

/**
 * Take HTML and give back the text part while dropping the HTML tags.
 *
 * There is some risk that using TagSoup means we'll permute non-HTML text.
 * However, it seems to work the best so far in test cases.
 *
 * @author dan
 * @see <a href="http://home.ccil.org/~cowan/XML/tagsoup/">TagSoup</a> 
 */
public class Html2Text2 implements ContentHandler {
private StringBuffer sb;

public Html2Text2() {
}

public void parse(String str) throws IOException, SAXException {
    XMLReader reader = new Parser();
    reader.setContentHandler(this);
    sb = new StringBuffer();
    reader.parse(new InputSource(new StringReader(str)));
}

public String getText() {
    return sb.toString();
}

@Override
public void characters(char[] ch, int start, int length)
    throws SAXException {
    for (int idx = 0; idx < length; idx++) {
    sb.append(ch[idx+start]);
    }
}

@Override
public void ignorableWhitespace(char[] ch, int start, int length)
    throws SAXException {
    sb.append(ch);
}

// The methods below do not contribute to the text
@Override
public void endDocument() throws SAXException {
}

@Override
public void endElement(String uri, String localName, String qName)
    throws SAXException {
}

@Override
public void endPrefixMapping(String prefix) throws SAXException {
}


@Override
public void processingInstruction(String target, String data)
    throws SAXException {
}

@Override
public void setDocumentLocator(Locator locator) {
}

@Override
public void skippedEntity(String name) throws SAXException {
}

@Override
public void startDocument() throws SAXException {
}

@Override
public void startElement(String uri, String localName, String qName,
    Attributes atts) throws SAXException {
}

@Override
public void startPrefixMapping(String prefix, String uri)
    throws SAXException {
}
}

答案 12 :(得分:4)

我知道这已经过时了,但我正在制作一个项目,要求我过滤HTML,这很好用:

noHTMLString.replaceAll("\\&.*?\\;", "");

而不是:

html = html.replaceAll("&nbsp;","");
html = html.replaceAll("&amp;"."");

答案 13 :(得分:4)

这是一个更轻松的更新,试图处理中断和列表的一些格式。我用Amaya的输出作为指导。

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.Stack;
import java.util.logging.Logger;

import javax.swing.text.MutableAttributeSet;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.parser.ParserDelegator;

public class HTML2Text extends HTMLEditorKit.ParserCallback {
    private static final Logger log = Logger
            .getLogger(Logger.GLOBAL_LOGGER_NAME);

    private StringBuffer stringBuffer;

    private Stack<IndexType> indentStack;

    public static class IndexType {
        public String type;
        public int counter; // used for ordered lists

        public IndexType(String type) {
            this.type = type;
            counter = 0;
        }
    }

    public HTML2Text() {
        stringBuffer = new StringBuffer();
        indentStack = new Stack<IndexType>();
    }

    public static String convert(String html) {
        HTML2Text parser = new HTML2Text();
        Reader in = new StringReader(html);
        try {
            // the HTML to convert
            parser.parse(in);
        } catch (Exception e) {
            log.severe(e.getMessage());
        } finally {
            try {
                in.close();
            } catch (IOException ioe) {
                // this should never happen
            }
        }
        return parser.getText();
    }

    public void parse(Reader in) throws IOException {
        ParserDelegator delegator = new ParserDelegator();
        // the third parameter is TRUE to ignore charset directive
        delegator.parse(in, this, Boolean.TRUE);
    }

    public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) {
        log.info("StartTag:" + t.toString());
        if (t.toString().equals("p")) {
            if (stringBuffer.length() > 0
                    && !stringBuffer.substring(stringBuffer.length() - 1)
                            .equals("\n")) {
                newLine();
            }
            newLine();
        } else if (t.toString().equals("ol")) {
            indentStack.push(new IndexType("ol"));
            newLine();
        } else if (t.toString().equals("ul")) {
            indentStack.push(new IndexType("ul"));
            newLine();
        } else if (t.toString().equals("li")) {
            IndexType parent = indentStack.peek();
            if (parent.type.equals("ol")) {
                String numberString = "" + (++parent.counter) + ".";
                stringBuffer.append(numberString);
                for (int i = 0; i < (4 - numberString.length()); i++) {
                    stringBuffer.append(" ");
                }
            } else {
                stringBuffer.append("*   ");
            }
            indentStack.push(new IndexType("li"));
        } else if (t.toString().equals("dl")) {
            newLine();
        } else if (t.toString().equals("dt")) {
            newLine();
        } else if (t.toString().equals("dd")) {
            indentStack.push(new IndexType("dd"));
            newLine();
        }
    }

    private void newLine() {
        stringBuffer.append("\n");
        for (int i = 0; i < indentStack.size(); i++) {
            stringBuffer.append("    ");
        }
    }

    public void handleEndTag(HTML.Tag t, int pos) {
        log.info("EndTag:" + t.toString());
        if (t.toString().equals("p")) {
            newLine();
        } else if (t.toString().equals("ol")) {
            indentStack.pop();
            ;
            newLine();
        } else if (t.toString().equals("ul")) {
            indentStack.pop();
            ;
            newLine();
        } else if (t.toString().equals("li")) {
            indentStack.pop();
            ;
            newLine();
        } else if (t.toString().equals("dd")) {
            indentStack.pop();
            ;
        }
    }

    public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos) {
        log.info("SimpleTag:" + t.toString());
        if (t.toString().equals("br")) {
            newLine();
        }
    }

    public void handleText(char[] text, int pos) {
        log.info("Text:" + new String(text));
        stringBuffer.append(text);
    }

    public String getText() {
        return stringBuffer.toString();
    }

    public static void main(String args[]) {
        String html = "<html><body><p>paragraph at start</p>hello<br />What is happening?<p>this is a<br />mutiline paragraph</p><ol>  <li>This</li>  <li>is</li>  <li>an</li>  <li>ordered</li>  <li>list    <p>with</p>    <ul>      <li>another</li>      <li>list        <dl>          <dt>This</dt>          <dt>is</dt>            <dd>sdasd</dd>            <dd>sdasda</dd>            <dd>asda              <p>aasdas</p>            </dd>            <dd>sdada</dd>          <dt>fsdfsdfsd</dt>        </dl>        <dl>          <dt>vbcvcvbcvb</dt>          <dt>cvbcvbc</dt>            <dd>vbcbcvbcvb</dd>          <dt>cvbcv</dt>          <dt></dt>        </dl>        <dl>          <dt></dt>        </dl></li>      <li>cool</li>    </ul>    <p>stuff</p>  </li>  <li>cool</li></ol><p></p></body></html>";
        System.out.println(convert(html));
    }
}

答案 14 :(得分:4)

或者,可以使用HtmlCleaner

private CharSequence removeHtmlFrom(String html) {
    return new HtmlCleaner().clean(html).getText();
}

答案 15 :(得分:3)

这里是替换所有内容的另一种方式(HTML标签| HTML实体| HTML内容中的空白)

content.replaceAll("(<.*?>)|(&.*?;)|([ ]{2,})", "");,其中content是一个字符串。

答案 16 :(得分:3)

另一种方法是使用com.google.gdata.util.common.html.HtmlToText类 喜欢

MyWriter.toConsole(HtmlToText.htmlToPlainText(htmlResponse));

这不是防弹代码,当我在维基百科条目上运行时,我也得到了样式信息。但是,我相信小型/简单的工作会有效。

答案 17 :(得分:3)

这是另一种方法:

public static String removeHTML(String input) {
    int i = 0;
    String[] str = input.split("");

    String s = "";
    boolean inTag = false;

    for (i = input.indexOf("<"); i < input.indexOf(">"); i++) {
        inTag = true;
    }
    if (!inTag) {
        for (i = 0; i < str.length; i++) {
            s = s + str[i];
        }
    }
    return s;
}

答案 18 :(得分:3)

听起来你想要从HTML转到纯文本 如果是这种情况,请访问www.htmlparser.org。这是一个从URL中找到的html文件中删除所有标记的示例 它使用 org.htmlparser.beans.StringBean

static public String getUrlContentsAsText(String url) {
    String content = "";
    StringBean stringBean = new StringBean();
    stringBean.setURL(url);
    content = stringBean.getStrings();
    return content;
}

答案 19 :(得分:2)

也可以使用Apache Tika来实现此目的。默认情况下,它会保留剥离的html中的空格,这在某些情况下可能是需要的:

InputStream htmlInputStream = ..
HtmlParser htmlParser = new HtmlParser();
HtmlContentHandler htmlContentHandler = new HtmlContentHandler();
htmlParser.parse(htmlInputStream, htmlContentHandler, new Metadata())
System.out.println(htmlContentHandler.getBodyText().trim())

答案 20 :(得分:1)

使用JSoup保留换行信息的一种方法是在所有新行标记之前加上一些虚拟字符串,执行JSoup并用“\ n”替换虚拟字符串。

String html = "<p>Line one</p><p>Line two</p>Line three<br/>etc.";
String NEW_LINE_MARK = "NEWLINESTART1234567890NEWLINEEND";
for (String tag: new String[]{"</p>","<br/>","</h1>","</h2>","</h3>","</h4>","</h5>","</h6>","</li>"}) {
    html = html.replace(tag, NEW_LINE_MARK+tag);
}

String text = Jsoup.parse(html).text();

text = text.replace(NEW_LINE_MARK + " ", "\n\n");
text = text.replace(NEW_LINE_MARK, "\n\n");

答案 21 :(得分:1)

您可以简单地使用Android的默认HTML过滤器

    public String htmlToStringFilter(String html){

    return Html.fromHtml(textToFilter).toString();

    }

上述方法将为您的输入返回经过HTML过滤的字符串。

答案 22 :(得分:0)

要获得格式化的普通html文字,您可以这样做:

String BR_ESCAPED = "&lt;br/&gt;";
Element el=Jsoup.parse(html).select("body");
el.select("br").append(BR_ESCAPED);
el.select("p").append(BR_ESCAPED+BR_ESCAPED);
el.select("h1").append(BR_ESCAPED+BR_ESCAPED);
el.select("h2").append(BR_ESCAPED+BR_ESCAPED);
el.select("h3").append(BR_ESCAPED+BR_ESCAPED);
el.select("h4").append(BR_ESCAPED+BR_ESCAPED);
el.select("h5").append(BR_ESCAPED+BR_ESCAPED);
String nodeValue=el.text();
nodeValue=nodeValue.replaceAll(BR_ESCAPED, "<br/>");
nodeValue=nodeValue.replaceAll("(\\s*<br[^>]*>){3,}", "<br/><br/>");

要获取格式化纯文本,请更改&lt; br /&gt;通过\ n并更改最后一行:

nodeValue=nodeValue.replaceAll("(\\s*\n){3,}", "<br/><br/>");

答案 23 :(得分:0)

我的5美分:

String[] temp = yourString.split("&amp;");
String tmp = "";
if (temp.length > 1) {

    for (int i = 0; i < temp.length; i++) {
        tmp += temp[i] + "&";
    }
    yourString = tmp.substring(0, tmp.length() - 1);
}

答案 24 :(得分:0)

ex:classeString.replaceAll(&#34; \&lt;(/?[^ \&gt;] +)\&gt;&#34;,&#34; \&#34;)。replaceAll(&# 34; \ s +&#34;,&#34;&#34;)。trim()

答案 25 :(得分:0)

我知道问这个问题已经有一段时间了,但是我找到了另一种解决方案,这对我有用:

Pattern REMOVE_TAGS = Pattern.compile("<.+?>");
    Source source= new Source(htmlAsString);
 Matcher m = REMOVE_TAGS.matcher(sourceStep.getTextExtractor().toString());
                        String clearedHtml= m.replaceAll("");

答案 26 :(得分:0)

值得一提的是,如果您想在Service Stack项目中完成此任务,则它已经是内置的字符串扩展了

using ServiceStack.Text;
// ...
"The <b>quick</b> brown <p> fox </p> jumps over the lazy dog".StripHtml();

答案 27 :(得分:0)

我经常发现我只需要删除注释和脚本元素。对于我来说,这已经可靠地工作了15年,可以轻松扩展为处理HTML或XML中的任何元素名称:

// delete all comments
response = response.replaceAll("<!--[^>]*-->", "");
// delete all script elements
response = response.replaceAll("<(script|SCRIPT)[^+]*?>[^>]*?<(/script|SCRIPT)>", "");

答案 28 :(得分:0)

有时html字符串来自带有此类&lt的xml。使用Jsoup时,我们需要对其进行解析,然后对其进行清理。

Document doc = Jsoup.parse(htmlstrl);
Whitelist wl = Whitelist.none();
String plain = Jsoup.clean(doc.text(), wl);

仅使用Jsoup.parse(htmlstrl).text()不能删除标签。

答案 29 :(得分:0)

尝试使用javascript:

const strippedString = htmlString.replace(/(<([^>]+)>)/gi, "");
console.log(strippedString);

答案 30 :(得分:0)

您可以使用此方法从字符串中删除 HTML 标签,

public static String stripHtmlTags(String html) {

    return html.replaceAll("<.*?>", "");

}

答案 31 :(得分:-1)

从字符串中删除HTML标记。在某个地方我们需要解析一些字符串,这些字符串会被某些响应接收,例如来自服务器的Httpresponse。

所以我们需要解析它。

这里我将展示如何从字符串中删除html标记。

    // sample text with tags

    string str = "<html><head>sdfkashf sdf</head><body>sdfasdf</body></html>";



    // regex which match tags

    System.Text.RegularExpressions.Regex rx = new System.Text.RegularExpressions.Regex("<[^>]*>");



    // replace all matches with empty strin

    str = rx.Replace(str, "");



    //now str contains string without html tags

答案 32 :(得分:-1)

你可以简单地使用多个replaceAll()来创建一个方法,如

String RemoveTag(String html){
   html = html.replaceAll("\\<.*?>","")
   html = html.replaceAll("&nbsp;","");
   html = html.replaceAll("&amp;"."");
   ----------
   ----------
   return html;
}

将此链接用于您需要的最常见替换: http://tunes.org/wiki/html_20special_20characters_20and_20symbols.html

简单但有效。我首先使用此方法删除垃圾但不是第一行,即replaceAll(“\&lt;。*?&gt;”,“”),后来我使用特定关键字搜索索引,然后使用.substring(start) ,结束)剥离不必要的东西的方法。由于这更加强大,您可以精确指出整个html页面中所需的内容。