web-dev-qa-db-fra.com

Supprimer les balises HTML d'une chaîne

Existe-t-il un bon moyen de supprimer le code HTML d'une chaîne Java? Une regex simple comme

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

fonctionnera, mais des éléments tels que &amp; ne seront pas convertis correctement et les caractères non HTML entre les deux chevrons seront supprimés (c’est-à-dire que .*? dans la regex disparaîtra).

403
Mason

Utilisez un analyseur HTML au lieu de regex. C'est simple avec Jsoup .

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

Jsoup a également prend en charge la suppression des balises HTML par rapport à une liste blanche personnalisable, ce qui est très utile si vous souhaitez autoriser uniquement, par exemple. <b>, <i> et <u>.

Voir également:

539
BalusC

Si vous écrivez pour Android vous pouvez le faire ...

Android.text.Html.fromHtml(instruction).toString()
265
Ken Goodridge

Si l'utilisateur entre <b>hey!</b>, voulez-vous afficher <b>hey!</b> ou hey!? Si le premier, échappez less-thans, et l'esperluette HTML (et éventuellement guillemets) et tout va bien. Une modification de votre code pour implémenter la deuxième option serait:

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

mais vous rencontrerez des problèmes si l'utilisateur entre quelque chose de mal formé, comme <bhey!</b>.

Vous pouvez également vérifier JTidy qui analysera les entrées HTML "sales" et devrait vous permettre de supprimer les balises tout en conservant le texte.

Le problème en essayant de supprimer le code HTML est que les navigateurs ont des analyseurs syntaxiques très indulgents, plus indulgents que n'importe quelle bibliothèque que vous pouvez trouver, donc même si vous faites de votre mieux pour supprimer toutes les balises (en utilisant la méthode de remplacement ci-dessus, une bibliothèque DOM ou JTidy). , vous devez toujours vous assurer de coder tous les caractères spéciaux HTML restants pour protéger votre sortie.

78

Une autre méthode consiste à utiliser javax.swing.text.html.HTMLEditorKit pour extraire le texte.

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: supprime les balises HTML d'un fichier pour extraire uniquement le texte

28
RealHowTo

Je pense que le moyen le plus simple de filtrer les balises html est:

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("");
}
24
Serge

Aussi très simple en utilisant Jericho , et vous pouvez conserver une partie de la mise en forme (sauts de ligne et liens, par exemple).

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

Sur Android, essayez ceci:

String result = Html.fromHtml(html).toString();
15
Ameen Maheen

La réponse acceptée de faire simplement Jsoup.parse(html).text() a deux problèmes potentiels (avec JSoup 1.7.3):

  • Il supprime les sauts de ligne du texte
  • Il convertit le texte &lt;script&gt; en <script>

Si vous utilisez ceci pour vous protéger contre XSS, c'est un peu gênant. Voici mon meilleur coup pour une solution améliorée, utilisant à la fois JSoup et 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);

Notez que la dernière étape est parce que je dois utiliser la sortie en texte brut. Si vous n'avez besoin que d'une sortie HTML, vous devriez pouvoir le supprimer.

Et voici un tas de cas de test (entrée à sortie):

{"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"}

Si vous trouvez un moyen de l'améliorer, faites-le moi savoir.

12
Damien

Il est très difficile d'échapper à HTML correctement. Je suggérerais certainement d'utiliser un code de bibliothèque pour le faire, car il est beaucoup plus subtil que vous ne le pensez. Jetez un œil à StringEscapeUtils d’Apache pour une très bonne bibliothèque permettant de gérer cela en Java.

12
Tim Howland

Cela devrait marcher -

utilisez ceci

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

et ça

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

Vous voudrez peut-être remplacer les balises <br/> et </p> par des nouvelles lignes avant de supprimer le code HTML afin d'éviter qu'il ne devienne un désordre illisible, comme le suggère Tim.

La seule façon pour moi de supprimer les balises HTML tout en laissant les non-HTML entre crochets serait de vérifier par un liste de balises HTML . Quelque chose dans ce sens ...

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

Puis décoder HTML des caractères spéciaux tels que &amp;. Le résultat ne doit pas être considéré comme étant désinfecté.

6
foxy

Voici une autre variante de la façon de remplacer tous (balises HTML | Entités HTML | Espace vide dans le contenu HTML)

content.replaceAll("(<.*?>)|(&.*?;)|([ ]{2,})", ""); où le contenu est une chaîne.

4
silentsudo

La réponse acceptée ne fonctionnait pas pour moi pour le cas de test que j'ai indiqué: le résultat de "a <b ou b> c" est "a b ou b> c".

Donc, j'ai utilisé TagSoup à la place. Voici une photo qui a fonctionné pour mon cas de test (et quelques autres):

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 {
}
}
4
dfrankow

Je sais que c'est vieux, mais je travaillais sur un projet qui nécessitait que je filtre du HTML et cela a bien fonctionné:

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

au lieu de cela:

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

Alternativement, on peut utiliser HtmlCleaner :

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

Utilisez Html.fromHtml

HTML Les balises sont

_<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>
_

Selon Documentations officielles d'Android toutes les balises du HTML s'afficheront comme un remplacement générique String quel est votre programme peut alors passer et remplacer par real chaînes .

La méthode Html.formHtml utilise comme argument Html.TagHandler et Html.ImageGetter, ainsi que le texte à analyser.

Exemple

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

Ensuite

_Your_TextView_Obj.setText(Html.fromHtml(Str_Html).toString());
_

Sortie

Ceci est un texte que l'utilisateur peut mettre dans son profil

4
IntelliJ Amiya

Voici une mise à jour légèrement plus complète pour essayer de gérer le formatage des pauses et des listes. J'ai utilisé la sortie d'Amaya comme guide.

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));
    }
}
4
Mike

Une autre méthode consiste à utiliser la classe com.google.gdata.util.common.html.HtmlToText comme

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

Ce n'est pas un code à l'épreuve des balles et quand je le lance sur des entrées wikipedia, je reçois aussi des informations sur le style. Cependant, je crois que pour les petits travaux/simples, cela serait efficace.

3
rjha94

Voici une autre façon de le faire:

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

On dirait que vous voulez passer du HTML au texte brut.
Si tel est le cas, consultez le site www.htmlparser.org. Voici un exemple qui supprime toutes les balises du fichier html situé à une URL.
Il utilise org.htmlparser.beans.StringBean.

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

Vous pouvez simplement utiliser le filtre HTML par défaut d'Android

    public String htmlToStringFilter(String textToFilter){

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

    }

La méthode ci-dessus renverra la chaîne filtrée HTML pour votre entrée.

2
Anuraganu Punalur

On pourrait aussi utiliser Apache Tika à cette fin. Par défaut, il préserve les espaces du code HTML dépouillé, ce qui peut être souhaité dans certaines situations:

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

Une façon de conserver les informations de nouvelle ligne avec JSoup consiste à faire précéder toutes les nouvelles balises de ligne par une chaîne factice, à exécuter JSoup et à remplacer la chaîne factice par "\ 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");
1
RobMen
classeString.replaceAll("\\<(/?[^\\>]+)\\>", "\\ ").replaceAll("\\s+", " ").trim() 
0
Guilherme Oliveira

Pour obtenir texte html ordinaire formaté vous pouvez le faire:

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

Pour obtenir texte brut formaté changer <br/> par\n et changer la dernière ligne de:

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

Mes 5 centimes:

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);
}
0
Alexander