Question

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 comme &amp; ne seront pas convertis correctement et les caractères non HTML entre les deux chevrons seront supprimés (c.-à-d. le .*? dans l'expression régulière disparaîtra).

Était-ce utile?

La solution

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 pris en charge la suppression des balises HTML dans une liste blanche personnalisable, ce qui est très utile. utile si vous voulez n'autoriser que par exemple <b>, <i> et <u>.

Voir aussi:

Autres conseils

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

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

Si l'utilisateur entre <b>hey!</b>, voulez-vous afficher hey! ou <bhey!</b>? Si le premier, échappez less-thans, et html-encoder (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 <=>.

Vous pouvez également consulter JTidy , qui analysera & "; sale &"; HTML, 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. Ainsi, même si vous faites de votre mieux pour supprimer toutes les balises ou JTidy), vous devez toujours vous assurer de coder tous les caractères spéciaux HTML restants afin de protéger votre sortie.

Vous pouvez également 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: Supprimer les balises HTML d'un fichier pour extraire uniquement le texte TEXT

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

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

Également très simple avec Jericho , vous pouvez conserver une partie de la mise en forme (ligne pauses 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());

Sous Android, essayez ceci:

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

HTML Echapper est vraiment difficile à faire 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. Découvrez les StringEscapeUtils d'Apache. pour une très bonne bibliothèque pour gérer cela en Java.

La réponse acceptée de faire simplement Jsoup.parse(html).text() comporte 2 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 tant que texte brut. Si vous n’avez besoin que d’une sortie HTML, vous devriez pouvoir le supprimer.

Et voici quelques 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 le moyen de l'améliorer, faites-le-moi savoir.

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 caractères non HTML entre crochets serait de vérifier avec liste des 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 désinfecté.

Cela devrait fonctionner -

utiliser ceci

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

et cela

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

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

J'ai donc 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 {
}
}

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

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

au lieu de ceci:

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

Voici une mise à jour légèrement plus détaillée pour essayer de gérer le formatage des sauts 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));
    }
}

Vous pouvez également utiliser HtmlCleaner :

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

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 Android & # 8217; Les documentations officielles des balises du HTML s'affichent sous la forme d'une chaîne générique que votre programme peut ensuite parcourir et remplacer par de véritables chaînes .

La méthode

Html.formHtml prend comme arguments 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> ";

Alors

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

Sortie

Il s'agit d'un texte me concernant que l'utilisateur peut insérer dans son profil

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 du code à toute épreuve et lorsque je le lance sur des entrées wikipedia, je reçois également des informations sur le style. Cependant, je crois que pour les petits travaux / simples, cela serait efficace.

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

Voici une autre façon de procéder:

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

Voici une variante supplémentaire de la procédure de remplacement de tous les éléments (balises HTML | Entités HTML | Espace vide dans le contenu HTML)

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

On pourrait également utiliser Apache Tika à cette fin. Par défaut, il préserve les espaces du 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())

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 fictive, à exécuter JSoup et à remplacer la chaîne fictive 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");

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 renvoie la chaîne filtrée HTML pour votre entrée.

Mes 5 cents:

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

Pour obtenir du texte HTML brut formaté , procédez comme suit:

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 du texte brut formaté , changez < br / > par \ n et changez la dernière ligne par:

nodeValue=nodeValue.replaceAll("(\\s*\n){3,}", "<br/><br/>");
classeString.replaceAll("\\<(/?[^\\>]+)\\>", "\\ ").replaceAll("\\s+", " ").trim() 

vous pouvez simplement créer une méthode avec plusieurs replaceAll () comme

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

Utilisez ce lien pour les remplacements les plus courants dont vous avez besoin:

C'est simple mais efficace. J'utilise cette méthode d'abord pour supprimer les fichiers indésirables, mais pas la toute première ligne, c'est-à-dire replaceAll (& "; \ & Lt;. *? & Gt; &"; & "; quot;), et plus tard, j’utilise des mots-clés spécifiques pour rechercher des index, puis la méthode .substring (début, fin) pour éliminer les éléments inutiles. Comme cela est plus robuste et que vous pouvez identifier exactement ce dont vous avez besoin dans l’ensemble de la page html.

Supprimer les balises HTML de la chaîne. Quelque part, nous devons analyser une chaîne reçue par certaines réponses telles que Httpresponse du serveur.

Nous devons donc l'analyser.

Ici, je vais montrer comment supprimer les balises HTML de la chaîne.

    // 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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top