2009-06-15 8 views
106

Grundsätzlich möchte ich ein bestimmtes HTML-Dokument zu dekodieren, und alle Sonderzeichen, wie "&nbsp" ->" ", ">" ->">" ersetzen.Java: Wie entwirrt man HTML-Zeichen-Entitäten in Java?

In .NET können wir HttpUtility.HtmlDecode verwenden.

Was ist die äquivalente Funktion in Java?

+4

  heißt Zeichenentität. Bearbeitete den Titel. –

Antwort

144

Ich habe die Apache Commons StringEscapeUtils.unescapeHtml4() für benutzten:

demaskiert einen String Einheit Fluchten in eine Zeichenfolge enthält, die tatsächlichen Unicode-Zeichen enthalten den Fluchten entspricht. Unterstützt HTML 4.0-Entitäten.

+15

Leider habe ich heute festgestellt, dass es HTMLSpecial Zeichen nicht sehr gut decodiert :( – Sid

+1

ein schmutziger Trick ist es, den Wert zunächst in einem versteckten Feld zu speichern, dann sollte das Zielfeld den Wert aus dem versteckten Feld bekommen. – Joset

-7

Incase wollen Sie imitieren, was PHP-Funktion htmlspecialchars_decode tut PHP-Funktion get_html_translation_table() verwenden, um die Tabelle zu entleeren und dann den Java-Code verwenden, wie,

static Map<String,String> html_specialchars_table = new Hashtable<String,String>(); 
static { 
     html_specialchars_table.put("&lt;","<"); 
     html_specialchars_table.put("&gt;",">"); 
     html_specialchars_table.put("&amp;","&"); 
} 
static String htmlspecialchars_decode_ENT_NOQUOTES(String s){ 
     Enumeration en = html_specialchars_table.keys(); 
     while(en.hasMoreElements()){ 
       String key = en.nextElement(); 
       String val = html_specialchars_table.get(key); 
       s = s.replaceAll(key, val); 
     } 
     return s; 
} 
+5

Don nicht so viel, verwenden Sie Generika auf dieser HashMap! Verwenden Sie auch eine Foreach, nicht eine Weile, um zu iterieren, der Code wird viel besser lesbar aussehen! – WhyNotHugo

+3

@BalaDutt, wenn Sie Ihre Antwort verbessern, werden die Jungs Ihnen Punkte geben :) – Spider

+2

Verbessere auch deine Funktions- und Variablennamen, @Bala. –

0

Betrachten Sie die HtmlManipulator Java-Klasse. Möglicherweise müssen Sie einige Elemente hinzufügen (nicht alle Elemente sind in der Liste).

Die Apache Commons StringEscapeUtils, wie von Kevin Hakanson vorgeschlagen, funktionierte nicht 100% für mich; einige Entitäten wie & # 145 (linkes einfaches Zitat) wurden irgendwie in '222' übersetzt. Ich habe auch versucht, org.jsoup, und hatte das gleiche Problem.

28

Ich versuchte Apache Commons StringEscapeUtils.unescapeHtml3() in meinem Projekt, war aber nicht mit seiner Leistung zufrieden. Es stellt sich heraus, dass es viele unnötige Operationen durchführt. Zum einen weist es für jeden Aufruf einen StringWriter zu, auch wenn in der Zeichenfolge nichts zu unescape ist. Ich habe diesen Code anders geschrieben, jetzt funktioniert es viel schneller. Wer das in Google findet, kann es gerne verwenden.

Der folgende Code unescapes alle HTML 3 Symbole und numerische Escapes (entspricht Apache unescapeHtml3). Sie können nur mehr Einträge auf der Karte hinzufügen, wenn Sie HTML benötigen 4.

package com.example; 

import java.io.StringWriter; 
import java.util.HashMap; 

public class StringUtils { 

    public static final String unescapeHtml3(final String input) { 
     StringWriter writer = null; 
     int len = input.length(); 
     int i = 1; 
     int st = 0; 
     while (true) { 
      // look for '&' 
      while (i < len && input.charAt(i-1) != '&') 
       i++; 
      if (i >= len) 
       break; 

      // found '&', look for ';' 
      int j = i; 
      while (j < len && j < i + MAX_ESCAPE + 1 && input.charAt(j) != ';') 
       j++; 
      if (j == len || j < i + MIN_ESCAPE || j == i + MAX_ESCAPE + 1) { 
       i++; 
       continue; 
      } 

      // found escape 
      if (input.charAt(i) == '#') { 
       // numeric escape 
       int k = i + 1; 
       int radix = 10; 

       final char firstChar = input.charAt(k); 
       if (firstChar == 'x' || firstChar == 'X') { 
        k++; 
        radix = 16; 
       } 

       try { 
        int entityValue = Integer.parseInt(input.substring(k, j), radix); 

        if (writer == null) 
         writer = new StringWriter(input.length()); 
        writer.append(input.substring(st, i - 1)); 

        if (entityValue > 0xFFFF) { 
         final char[] chrs = Character.toChars(entityValue); 
         writer.write(chrs[0]); 
         writer.write(chrs[1]); 
        } else { 
         writer.write(entityValue); 
        } 

       } catch (NumberFormatException ex) { 
        i++; 
        continue; 
       } 
      } 
      else { 
       // named escape 
       CharSequence value = lookupMap.get(input.substring(i, j)); 
       if (value == null) { 
        i++; 
        continue; 
       } 

       if (writer == null) 
        writer = new StringWriter(input.length()); 
       writer.append(input.substring(st, i - 1)); 

       writer.append(value); 
      } 

      // skip escape 
      st = j + 1; 
      i = st; 
     } 

     if (writer != null) { 
      writer.append(input.substring(st, len)); 
      return writer.toString(); 
     } 
     return input; 
    } 

    private static final String[][] ESCAPES = { 
     {"\"",  "quot"}, // " - double-quote 
     {"&",  "amp"}, // & - ampersand 
     {"<",  "lt"}, // < - less-than 
     {">",  "gt"}, // > - greater-than 

     // Mapping to escape ISO-8859-1 characters to their named HTML 3.x equivalents. 
     {"\u00A0", "nbsp"}, // non-breaking space 
     {"\u00A1", "iexcl"}, // inverted exclamation mark 
     {"\u00A2", "cent"}, // cent sign 
     {"\u00A3", "pound"}, // pound sign 
     {"\u00A4", "curren"}, // currency sign 
     {"\u00A5", "yen"}, // yen sign = yuan sign 
     {"\u00A6", "brvbar"}, // broken bar = broken vertical bar 
     {"\u00A7", "sect"}, // section sign 
     {"\u00A8", "uml"}, // diaeresis = spacing diaeresis 
     {"\u00A9", "copy"}, // © - copyright sign 
     {"\u00AA", "ordf"}, // feminine ordinal indicator 
     {"\u00AB", "laquo"}, // left-pointing double angle quotation mark = left pointing guillemet 
     {"\u00AC", "not"}, // not sign 
     {"\u00AD", "shy"}, // soft hyphen = discretionary hyphen 
     {"\u00AE", "reg"}, // ® - registered trademark sign 
     {"\u00AF", "macr"}, // macron = spacing macron = overline = APL overbar 
     {"\u00B0", "deg"}, // degree sign 
     {"\u00B1", "plusmn"}, // plus-minus sign = plus-or-minus sign 
     {"\u00B2", "sup2"}, // superscript two = superscript digit two = squared 
     {"\u00B3", "sup3"}, // superscript three = superscript digit three = cubed 
     {"\u00B4", "acute"}, // acute accent = spacing acute 
     {"\u00B5", "micro"}, // micro sign 
     {"\u00B6", "para"}, // pilcrow sign = paragraph sign 
     {"\u00B7", "middot"}, // middle dot = Georgian comma = Greek middle dot 
     {"\u00B8", "cedil"}, // cedilla = spacing cedilla 
     {"\u00B9", "sup1"}, // superscript one = superscript digit one 
     {"\u00BA", "ordm"}, // masculine ordinal indicator 
     {"\u00BB", "raquo"}, // right-pointing double angle quotation mark = right pointing guillemet 
     {"\u00BC", "frac14"}, // vulgar fraction one quarter = fraction one quarter 
     {"\u00BD", "frac12"}, // vulgar fraction one half = fraction one half 
     {"\u00BE", "frac34"}, // vulgar fraction three quarters = fraction three quarters 
     {"\u00BF", "iquest"}, // inverted question mark = turned question mark 
     {"\u00C0", "Agrave"}, // А - uppercase A, grave accent 
     {"\u00C1", "Aacute"}, // Б - uppercase A, acute accent 
     {"\u00C2", "Acirc"}, // В - uppercase A, circumflex accent 
     {"\u00C3", "Atilde"}, // Г - uppercase A, tilde 
     {"\u00C4", "Auml"}, // Д - uppercase A, umlaut 
     {"\u00C5", "Aring"}, // Е - uppercase A, ring 
     {"\u00C6", "AElig"}, // Ж - uppercase AE 
     {"\u00C7", "Ccedil"}, // З - uppercase C, cedilla 
     {"\u00C8", "Egrave"}, // И - uppercase E, grave accent 
     {"\u00C9", "Eacute"}, // Й - uppercase E, acute accent 
     {"\u00CA", "Ecirc"}, // К - uppercase E, circumflex accent 
     {"\u00CB", "Euml"}, // Л - uppercase E, umlaut 
     {"\u00CC", "Igrave"}, // М - uppercase I, grave accent 
     {"\u00CD", "Iacute"}, // Н - uppercase I, acute accent 
     {"\u00CE", "Icirc"}, // О - uppercase I, circumflex accent 
     {"\u00CF", "Iuml"}, // П - uppercase I, umlaut 
     {"\u00D0", "ETH"}, // Р - uppercase Eth, Icelandic 
     {"\u00D1", "Ntilde"}, // С - uppercase N, tilde 
     {"\u00D2", "Ograve"}, // Т - uppercase O, grave accent 
     {"\u00D3", "Oacute"}, // У - uppercase O, acute accent 
     {"\u00D4", "Ocirc"}, // Ф - uppercase O, circumflex accent 
     {"\u00D5", "Otilde"}, // Х - uppercase O, tilde 
     {"\u00D6", "Ouml"}, // Ц - uppercase O, umlaut 
     {"\u00D7", "times"}, // multiplication sign 
     {"\u00D8", "Oslash"}, // Ш - uppercase O, slash 
     {"\u00D9", "Ugrave"}, // Щ - uppercase U, grave accent 
     {"\u00DA", "Uacute"}, // Ъ - uppercase U, acute accent 
     {"\u00DB", "Ucirc"}, // Ы - uppercase U, circumflex accent 
     {"\u00DC", "Uuml"}, // Ь - uppercase U, umlaut 
     {"\u00DD", "Yacute"}, // Э - uppercase Y, acute accent 
     {"\u00DE", "THORN"}, // Ю - uppercase THORN, Icelandic 
     {"\u00DF", "szlig"}, // Я - lowercase sharps, German 
     {"\u00E0", "agrave"}, // а - lowercase a, grave accent 
     {"\u00E1", "aacute"}, // б - lowercase a, acute accent 
     {"\u00E2", "acirc"}, // в - lowercase a, circumflex accent 
     {"\u00E3", "atilde"}, // г - lowercase a, tilde 
     {"\u00E4", "auml"}, // д - lowercase a, umlaut 
     {"\u00E5", "aring"}, // е - lowercase a, ring 
     {"\u00E6", "aelig"}, // ж - lowercase ae 
     {"\u00E7", "ccedil"}, // з - lowercase c, cedilla 
     {"\u00E8", "egrave"}, // и - lowercase e, grave accent 
     {"\u00E9", "eacute"}, // й - lowercase e, acute accent 
     {"\u00EA", "ecirc"}, // к - lowercase e, circumflex accent 
     {"\u00EB", "euml"}, // л - lowercase e, umlaut 
     {"\u00EC", "igrave"}, // м - lowercase i, grave accent 
     {"\u00ED", "iacute"}, // н - lowercase i, acute accent 
     {"\u00EE", "icirc"}, // о - lowercase i, circumflex accent 
     {"\u00EF", "iuml"}, // п - lowercase i, umlaut 
     {"\u00F0", "eth"}, // р - lowercase eth, Icelandic 
     {"\u00F1", "ntilde"}, // с - lowercase n, tilde 
     {"\u00F2", "ograve"}, // т - lowercase o, grave accent 
     {"\u00F3", "oacute"}, // у - lowercase o, acute accent 
     {"\u00F4", "ocirc"}, // ф - lowercase o, circumflex accent 
     {"\u00F5", "otilde"}, // х - lowercase o, tilde 
     {"\u00F6", "ouml"}, // ц - lowercase o, umlaut 
     {"\u00F7", "divide"}, // division sign 
     {"\u00F8", "oslash"}, // ш - lowercase o, slash 
     {"\u00F9", "ugrave"}, // щ - lowercase u, grave accent 
     {"\u00FA", "uacute"}, // ъ - lowercase u, acute accent 
     {"\u00FB", "ucirc"}, // ы - lowercase u, circumflex accent 
     {"\u00FC", "uuml"}, // ь - lowercase u, umlaut 
     {"\u00FD", "yacute"}, // э - lowercase y, acute accent 
     {"\u00FE", "thorn"}, // ю - lowercase thorn, Icelandic 
     {"\u00FF", "yuml"}, // я - lowercase y, umlaut 
    }; 

    private static final int MIN_ESCAPE = 2; 
    private static final int MAX_ESCAPE = 6; 

    private static final HashMap<String, CharSequence> lookupMap; 
    static { 
     lookupMap = new HashMap<String, CharSequence>(); 
     for (final CharSequence[] seq : ESCAPES) 
      lookupMap.put(seq[1].toString(), seq[0]); 
    } 

} 
+0

Kürzlich musste ich ein langsames Struts-Projekt optimieren. Es stellte sich heraus, dass Struts unter dem Deckblatt Apache dafür aufruft, dass der HTML-String standardmäßig entwich (''). Durch das Deaktivieren von escaping ('') wurden einige Seiten um 5% bis 20% schneller ausgeführt. – Stephan

+0

Später fand ich heraus, dass dieser Code eine Schleife eingeben kann, wenn eine leere Zeichenfolge als Argument übergeben wird. Aktuelle Ausgabe hat dieses Problem behoben. –

+0

Ist diese Escape oder Unespace? & wird nicht dekodiert. Nur & wird zur Karte hinzugefügt, also funktioniert es nur in einer Richtung? – momomo

7

Die folgende Bibliothek kann auch für HTML in Java Flucht verwendet werden: unbescape.

HTML können auf diese Weise unescaped werden: i das Verfahren ersetzen verwenden

final String unescapedText = HtmlEscape.unescapeHtml(escapedText); 
+2

Es hat nichts zu tun: '% 3Chtml% 3E% 0D% 0A % 3Chead% 3E% 0D% 0A% 3Ctitle% 3E% 3C% 2Ftitle% 3E% 0D% 0A% 3C% 2Fhead% 3E% 0D% 0A% 3Körper% 3E% 0D% 0Atest% 0D% 0A% 3C% 2FKörper% 3E % 0D% 0A% 3C% 2Fhtml% 3E' – ThreaT

+26

@ThreaT Ihr Text ist nicht html-codiert, es ist URL-codiert –

-1

In meinem Fall durch jede Einheit in jeder Variablen testen, sieht mein Code wie folgt aus:

text = text.replace("&Ccedil;", "Ç"); 
text = text.replace("&ccedil;", "ç"); 
text = text.replace("&Aacute;", "Á"); 
text = text.replace("&Acirc;", "Â"); 
text = text.replace("&Atilde;", "Ã"); 
text = text.replace("&Eacute;", "É"); 
text = text.replace("&Ecirc;", "Ê"); 
text = text.replace("&Iacute;", "Í"); 
text = text.replace("&Ocirc;", "Ô"); 
text = text.replace("&Otilde;", "Õ"); 
text = text.replace("&Oacute;", "Ó"); 
text = text.replace("&Uacute;", "Ú"); 
text = text.replace("&aacute;", "á"); 
text = text.replace("&acirc;", "â"); 
text = text.replace("&atilde;", "ã"); 
text = text.replace("&eacute;", "é"); 
text = text.replace("&ecirc;", "ê"); 
text = text.replace("&iacute;", "í"); 
text = text.replace("&ocirc;", "ô"); 
text = text.replace("&otilde;", "õ"); 
text = text.replace("&oacute;", "ó"); 
text = text.replace("&uacute;", "ú"); 

In meinem Fall Das hat sehr gut funktioniert.

+1

Und wie verwalten Sie: & # 232 -> è ... und so weiter – Zofren

+0

Dies ist nicht nicht jede spezielle Entität, auch die beiden, die in der Frage erwähnt werden, fehlen. –

16

Die in anderen Antworten erwähnten Bibliotheken würden feine Lösungen sein, aber wenn man schon durch reale html in Ihrem Projekt passieren zu graben, das Jsoup Projekt viel mehr zu bieten hat als nur „Ampersand Pfund FFFF Semikolon Verwaltung " Dinge.

// textValue: <p>This is a&nbsp;sample. \"Granny\" Smith &#8211;.<\/p>\r\n 
// becomes this: This is a sample. "Granny" Smith –. 
// with one line of code: 
// Jsoup.parse(textValue).getText(); // for older versions of Jsoup 
Jsoup.parse(textValue).text(); 

// Another possibility may be the static unescapeEntities method: 
boolean strictMode = true; 
String unescapedString = org.jsoup.parser.Parser.unescapeEntities(textValue, strictMode); 

Und Sie auch die komfortable API zum Extrahieren und Bearbeiten von Daten erhalten, unter Verwendung der besten von DOM, CSS und jQuery-ähnliche Methoden. Es ist Open Source und MIT-Lizenz.

+2

upvote +, aber ich sollte darauf hinweisen, dass neuere Versionen von Jsoup '.text()' anstelle von '.getText()' – CodeBurner

+3

verwenden Vielleicht ist direkter zu verwenden 'org.jsoup.parser.Parser.unescapeEntities (String, boolean inAttribute) '. API-Dokumentation: https://jsoup.org/apidocs/org/jsoup/parser/Parser.html#unescapeEntities-java.lang.String-boolean- – danneu

+1

Dies war perfekt, da ich bereits Jsoup in meinem Projekt verwende. Auch @danneu hatte Recht - Parser.unescapeEntities funktioniert genau wie angekündigt. – MandisaW

2

Eine sehr einfache, aber ineffiziente Lösung ohne externe Bibliothek ist:

public static String unescapeHtml3(String str) { 
    try { 
     HTMLDocument doc = new HTMLDocument(); 
     new HTMLEditorKit().read(new StringReader("<html><body>" + str), doc, 0); 
     return doc.getText(1, doc.getLength()); 
    } catch(Exception ex) { 
     return str; 
    } 
} 

Dieses nur sollte verwenden, wenn Sie nur kleine Anzahl der Zeichenfolge zu entschlüsseln sind.

2

Dies hat den Job für mich,

import org.apache.commons.lang.StringEscapeUtils; 
... 
String decodedXML= StringEscapeUtils.unescapeHtml(encodedXML); 

oder

import org.apache.commons.lang3.StringEscapeUtils; 
... 
String decodedXML= StringEscapeUtils.unescapeHtml4(encodedXML); 

this helps :)

2

Der zuverlässigste Weg ist mit

String cleanedString = StringEscapeUtils.unescapeHtml4(originalString); 

von org.apache.commons.lang3.StringEscapeUtils .

Und die Whitespaces

cleanedString = cleanedString.trim(); 

Dies wird zu entkommen sicherzustellen, dass Whitespaces aufgrund in Web-Formularen kopieren und einfügen nicht in DB beibehalten werden.