@ Nonnull public static String urlDecode ( @ Nonnull final String sValue , @ Nonnull final Charset aCharset ) { ValueEnforcer . notNull ( sValue , "Value" ) ; ValueEnforcer . notNull ( aCharset , "Charset" ) ; boolean bNeedToChange = false ; final int nLen = sValue . length ( ) ; final StringBuilder aSB = new StringBuilder ( nLen ) ; int nIndex = 0 ; byte [ ] aBytes = null ; while ( nIndex < nLen ) { char c = sValue . charAt ( nIndex ) ; switch ( c ) { case ' ' : aSB . append ( ' ' ) ; nIndex ++ ; bNeedToChange = true ; break ; case ' ' : /* * Starting with this instance of %, process all consecutive * substrings of the form %xy. Each substring %xy will yield a byte. * Convert all consecutive bytes obtained this way to whatever * character(s) they represent in the provided encoding. */ try { // (numChars-i)/3 is an upper bound for the number // of remaining bytes if ( aBytes == null ) aBytes = new byte [ ( nLen - nIndex ) / 3 ] ; int nPos = 0 ; while ( ( nIndex + 2 ) < nLen && c == ' ' ) { final int nValue = Integer . parseInt ( sValue . substring ( nIndex + 1 , nIndex + 3 ) , 16 ) ; if ( nValue < 0 ) throw new IllegalArgumentException ( "URLDecoder: Illegal hex characters in escape (%) pattern - negative value" ) ; aBytes [ nPos ++ ] = ( byte ) nValue ; nIndex += 3 ; if ( nIndex < nLen ) c = sValue . charAt ( nIndex ) ; } // A trailing, incomplete byte encoding such as // "%x" will cause an exception to be thrown if ( nIndex < nLen && c == ' ' ) throw new IllegalArgumentException ( "URLDecoder: Incomplete trailing escape (%) pattern" ) ; aSB . append ( StringHelper . decodeBytesToChars ( aBytes , 0 , nPos , aCharset ) ) ; } catch ( final NumberFormatException e ) { throw new IllegalArgumentException ( "URLDecoder: Illegal hex characters in escape (%) pattern - " + e . getMessage ( ) ) ; } bNeedToChange = true ; break ; default : aSB . append ( c ) ; nIndex ++ ; break ; } } return bNeedToChange ? aSB . toString ( ) : sValue ; }
URL - decode the passed value automatically handling charset issues . The implementation is ripped from URLDecoder but does not throw an UnsupportedEncodingException for nothing .