public static String unescapeHtml ( String s ) { int amp = s . indexOf ( ' ' ) ; if ( amp < 0 ) { // Fast path. return s ; } int n = s . length ( ) ; StringBuilder sb = new StringBuilder ( n ) ; int pos = 0 ; do { // All numeric entities and all named entities can be represented in less than 12 chars, so // avoid any O(n**2) problem on "&&&&&&&&&" by not looking for ; more than 12 chars out. int end = - 1 ; int entityLimit = Math . min ( n , amp + 12 ) ; for ( int i = amp + 1 ; i < entityLimit ; ++ i ) { if ( s . charAt ( i ) == ' ' ) { end = i + 1 ; break ; } } int cp = - 1 ; if ( end == - 1 ) { cp = - 1 ; } else { if ( s . charAt ( amp + 1 ) == ' ' ) { // Decode a numeric entity char ch = s . charAt ( amp + 2 ) ; try { if ( ch == ' ' || ch == ' ' ) { // hex // & # x A B C D ; // ^ ^ ^ ^ ^ // amp + 0 1 2 3 end - 1 cp = Integer . parseInt ( s . substring ( amp + 3 , end - 1 ) , 16 ) ; } else { // decimal // & # 1 6 0 ; // ^ ^ ^ ^ // amp + 0 1 2 end - 1 cp = Integer . parseInt ( s . substring ( amp + 2 , end - 1 ) , 10 ) ; } } catch ( NumberFormatException ex ) { cp = - 1 ; // Malformed numeric entity } } else { // & q u o t ; // ^ ^ // amp end Integer cpI = HTML_ENTITY_TO_CODEPOINT . get ( s . substring ( amp , end ) ) ; cp = cpI != null ? cpI . intValue ( ) : - 1 ; } } if ( cp == - 1 ) { // Don't decode end = amp + 1 ; } else { sb . append ( s , pos , amp ) ; sb . appendCodePoint ( cp ) ; pos = end ; } amp = s . indexOf ( ' ' , end ) ; } while ( amp >= 0 ) ; return sb . append ( s , pos , n ) . toString ( ) ; }
Replace all the occurrences of HTML entities with the appropriate code - points .