Удалить теги HTML из строки

Есть ли хороший способ удалить HTML из строки Java? Простое регулярное выражение типа

 replaceAll("\\<.*?>","") 

будет работать, но такие вещи, как &amp;, не будут правильно преобразованы, а не HTML между двумя угловыми скобками будут удалены (т.е. .*? в регулярном выражении исчезнет).

Ответ 1

Используйте анализатор HTML вместо регулярных выражений. Это очень просто с Джоупом.

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

Jsoup также поддерживает удаление тегов HTML из настраиваемого белого списка, что очень полезно, если вы хотите разрешить только, например, <b>, <i> и <u>.

Смотрите также:

Ответ 2

Если вы пишете для Android, вы можете это сделать...

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

Ответ 3

Если пользователь вводит <b>hey!</b>, вы хотите отобразить <b>hey!</b> или hey!? Если первый, бежать менее-thans и html-encode амперсанды (и, возможно, кавычки), и все в порядке. Модификация вашего кода для реализации второго варианта:

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

но вы столкнетесь с проблемами, если пользователь вводит что-то неправильное, например <bhey!</b>.

Вы также можете проверить JTidy, который будет анализировать "грязный" html-ввод и должен дать вам способ удалить теги, сохраняя текст.

Проблема с попыткой разделить html заключается в том, что браузеры имеют очень мягкие парсеры, более мягкие, чем любая библиотека, которую вы можете найти, поэтому, даже если вы сделаете все возможное, чтобы удалить все теги (используя вышеперечисленный метод, библиотеку DOM, или JTidy), вам все равно нужно будет закодировать любые оставшиеся специальные символы HTML, чтобы обеспечить безопасность вывода.

Ответ 4

Другой способ - использовать 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();
        }
    }
}

ref: Удалите теги HTML из файла, чтобы извлечь только ТЕКСТ

Ответ 5

Я думаю, что самый простой способ фильтрации тегов 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("");
}

Ответ 6

Также очень просто использовать Jericho, и вы можете сохранить некоторые форматирования (например, разрывы строк и ссылки).

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

Ответ 7

На Android попробуйте следующее:

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

Ответ 8

HTML Escaping действительно сложно сделать правильно - я бы определенно предложил использовать библиотечный код для этого, так как он намного более тонкий, чем вы думаете. Проверьте Apache StringEscapeUtils для довольно хорошей библиотеки для обработки этого в Java.

Ответ 9

Принятый ответ просто 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"}

Если вы найдете способ сделать это лучше, сообщите мне.

Ответ 10

Возможно, вы захотите заменить теги <br/> и </p> символами новой строки перед тем, как удалить HTML-код, чтобы он не стал неразборчивым, как предполагает Тим.

Единственный способ, я могу думать об удалении тегов HTML, но оставляя не-HTML между угловыми скобками, будет проверяться на список тегов HTML. Что-то в этом роде...

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

Затем специальные символы HTML-декодирования, такие как &amp;. Результат не следует считать дезинфицированным.

Ответ 11

Это должно работать -

используйте этот

  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.

Ответ 12

Здесь приведено немного более подробное обновление, чтобы попытаться обработать некоторое форматирование для разрывов и списков. В качестве руководства я использовал выход 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));
    }
}

Ответ 13

Принятый ответ не помог мне для тестового примера, который я указал: результатом "a < b или b > c" является "a b или b > 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 {
}
}

Ответ 14

Я знаю, что это старый, но я просто работал над проектом, который требовал от меня фильтрации HTML, и это сработало нормально:

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

вместо этого:

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

Ответ 15

В качестве альтернативы можно использовать HtmlCleaner:

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

Ответ 16

Используйте Html.fromHtml

HTML Теги

<a href="…"> <b>,  <big>, <blockquote>, <br>, <cite>, <dfn>
<div align="…">,  <em>, <font size="…" color="…" face="…">
<h1>,  <h2>, <h3>, <h4>,  <h5>, <h6>
<i>, <p>, <small>
<strike>,  <strong>, <sub>, <sup>, <tt>, <u>

В соответствии с Официальные документы андроидов любые теги в HTML будут отображаться как родовая замена Строка, которую ваша программа может выполнить и заменить с помощью реальных строк.

Html.formHtml использует Html.TagHandler и Html.ImageGetter как аргументы, а также текст для разбора.

Пример

String Str_Html=" <p>This is about me text that the user can put into their profile</p> ";

Тогда

Your_TextView_Obj.setText(Html.fromHtml(Str_Html).toString());

Выход

Это текст обо мне, который пользователь может ввести в свой профиль

Ответ 17

Похоже, вы хотите перейти с HTML на обычный текст.
Если это так, посмотрите на www.htmlparser.org. Вот пример, который удаляет все теги из html файла, найденного по URL-адресу. Он использует org.htmlparser.beans.StringBean.

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

Ответ 18

Еще одним способом может быть использование класса com.google.gdata.util.common.html.HtmlToText как

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

Это не пуленепробиваемый код, хотя и когда я запускаю его в википедии, я также получаю информацию о стиле. Однако я считаю, что для небольших/простых рабочих мест это было бы эффективно.

Ответ 19

Вот еще один способ сделать это:

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;
}

Ответ 20

Вот еще один вариант того, как заменить все (HTML-теги | HTML-объекты | Пустое пространство в содержимом HTML)

content.replaceAll("(<.*?>)|(&.*?;)|([ ]{2,})", ""); где content - String.

Ответ 21

Для этой цели также можно использовать 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())

Ответ 22

Один из способов сохранить новую информацию с 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");

Ответ 23

Вы можете просто использовать HTML-фильтр Android по умолчанию

    public String htmlToStringFilter(String textToFilter){

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

    }

Приведенный выше метод вернет отфильтрованную строку HTML для вашего ввода.

Ответ 24

Мои 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);
}

Ответ 25

Чтобы получить formateded plain html text, вы можете сделать это:

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/>");

Чтобы получить сформированный простой текст change < br/ > на \n и измените последнюю строку на:

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

Ответ 26

classeString.replaceAll("\\<(/?[^\\>]+)\\>", "\\ ").replaceAll("\\s+", " ").trim() 

Ответ 27

вы можете просто сделать метод с несколькими 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 ( "\ <. *? > ", ""), А позже я использую определенные ключевые слова для поиска индексов, а затем использую .substring(start, end), чтобы удалить ненужные вещи. Поскольку это более устойчиво, и вы можете точно указать, что вам нужно на всей странице html.

Ответ 28

Удалить теги 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