Java Tutorial/Network/URLDecoder

Материал из Java эксперт
Версия от 05:03, 1 июня 2010; Admin (обсуждение | вклад) (1 версия)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

Converting text to be used within a URL

/*
 * JBoss DNA (http://www.jboss.org/dna)
 * See the COPYRIGHT.txt file distributed with this work for information
 * regarding copyright ownership.  Some portions may be licensed
 * to Red Hat, Inc. under one or more contributor license agreements.
 * See the AUTHORS.txt file in the distribution for a full listing of 
 * individual contributors. 
 *
 * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
 * is licensed to you under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * JBoss DNA is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.BitSet;
/**
 * An encoder useful for converting text to be used within a URL, as defined by Section 2.3 of . Note that this class does not encode a complete URL ({@link java.net.URLEncoder}
 * and {@link java.net.URLDecoder} should be used for such purposes).
 * 
 * @author Randall Hauch
 */
public class UrlEncoder  {
    /**
     * Data characters that are allowed in a URI but do not have a reserved purpose are called unreserved. These include upper and
     * lower case letters, decimal digits, and a limited set of punctuation marks and symbols.
     * 
     * <pre>
     * unreserved  = alphanum | mark
     * mark        = &quot;-&quot; | &quot;_&quot; | &quot;.&quot; | &quot;!&quot; | &quot;&tilde;&quot; | &quot;*&quot; | &quot;"&quot; | &quot;(&quot; | &quot;)&quot;
     * </pre>
     * 
     * Unreserved characters can be escaped without changing the semantics of the URI, but this should not be done unless the URI
     * is being used in a context that does not allow the unescaped character to appear.
     */
    private static final BitSet RFC2396_UNRESERVED_CHARACTERS = new BitSet(256);
    private static final BitSet RFC2396_UNRESERVED_WITH_SLASH_CHARACTERS;
    public static final char ESCAPE_CHARACTER = "%";
    static {
        RFC2396_UNRESERVED_CHARACTERS.set("a", "z" + 1);
        RFC2396_UNRESERVED_CHARACTERS.set("A", "Z" + 1);
        RFC2396_UNRESERVED_CHARACTERS.set("0", "9" + 1);
        RFC2396_UNRESERVED_CHARACTERS.set("-");
        RFC2396_UNRESERVED_CHARACTERS.set("_");
        RFC2396_UNRESERVED_CHARACTERS.set(".");
        RFC2396_UNRESERVED_CHARACTERS.set("!");
        RFC2396_UNRESERVED_CHARACTERS.set("~");
        RFC2396_UNRESERVED_CHARACTERS.set("*");
        RFC2396_UNRESERVED_CHARACTERS.set("\"");
        RFC2396_UNRESERVED_CHARACTERS.set("(");
        RFC2396_UNRESERVED_CHARACTERS.set(")");
        RFC2396_UNRESERVED_WITH_SLASH_CHARACTERS = (BitSet)RFC2396_UNRESERVED_CHARACTERS.clone();
        RFC2396_UNRESERVED_WITH_SLASH_CHARACTERS.set("/");
    }
    private boolean slashEncoded = true;
    /**
     * {@inheritDoc}
     */
    public String encode( String text ) {
        if (text == null) return null;
        if (text.length() == 0) return text;
        final BitSet safeChars = isSlashEncoded() ? RFC2396_UNRESERVED_CHARACTERS : RFC2396_UNRESERVED_WITH_SLASH_CHARACTERS;
        final StringBuilder result = new StringBuilder();
        final CharacterIterator iter = new StringCharacterIterator(text);
        for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) {
            if (safeChars.get(c)) {
                // Safe character, so just pass through ...
                result.append(c);
            } else {
                // The character is not a safe character, and must be escaped ...
                result.append(ESCAPE_CHARACTER);
                result.append(Character.toLowerCase(Character.forDigit(c / 16, 16)));
                result.append(Character.toLowerCase(Character.forDigit(c % 16, 16)));
            }
        }
        return result.toString();
    }
    /**
     * {@inheritDoc}
     */
    public String decode( String encodedText ) {
        if (encodedText == null) return null;
        if (encodedText.length() == 0) return encodedText;
        final StringBuilder result = new StringBuilder();
        final CharacterIterator iter = new StringCharacterIterator(encodedText);
        for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) {
            if (c == ESCAPE_CHARACTER) {
                boolean foundEscapedCharacter = false;
                // Found the first character in a potential escape sequence, so grab the next two characters ...
                char hexChar1 = iter.next();
                char hexChar2 = hexChar1 != CharacterIterator.DONE ? iter.next() : CharacterIterator.DONE;
                if (hexChar2 != CharacterIterator.DONE) {
                    // We found two more characters, but ensure they form a valid hexadecimal number ...
                    int hexNum1 = Character.digit(hexChar1, 16);
                    int hexNum2 = Character.digit(hexChar2, 16);
                    if (hexNum1 > -1 && hexNum2 > -1) {
                        foundEscapedCharacter = true;
                        result.append((char)(hexNum1 * 16 + hexNum2));
                    }
                }
                if (!foundEscapedCharacter) {
                    result.append(c);
                    if (hexChar1 != CharacterIterator.DONE) result.append(hexChar1);
                    if (hexChar2 != CharacterIterator.DONE) result.append(hexChar2);
                }
            } else {
                result.append(c);
            }
        }
        return result.toString();
    }
    /**
     * @return slashEncoded
     */
    public boolean isSlashEncoded() {
        return this.slashEncoded;
    }
    /**
     * @param slashEncoded Sets slashEncoded to the specified value.
     * @return this object, for method chaining
     */
    public UrlEncoder setSlashEncoded( boolean slashEncoded ) {
        this.slashEncoded = slashEncoded;
        return this;
    }
}





Converting x-www-form-urlencoded Data

import java.net.URLEncoder;
public class Main {
  public static void main(String[] argv) throws Exception {
     String line = URLEncoder.encode("name1", "UTF-8") + "=" + URLEncoder.encode("value1", "UTF-8");
  }
}





Decoding and encoding URLs

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.logging.Logger;

/**
 * Utility class for decoding and encoding URLs
 *
 */
public final class UrlUtils {
    
    private static final String[] RESERVED_CHARS = {"+"};
    private static final String[] ENCODED_CHARS = {"%2b"};
    
    private UrlUtils() {
        
    }
    /**
     * Decodes using URLDecoder - use when queries or form post values are decoded
     * @param value value to decode
     * @return
     */
    public static String urlDecode(String value) {
        try {
            value = URLDecoder.decode(value, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            System.out.println("UTF-8 encoding can not be used to decode " + value);          
        }
        return value;
    }
    
    /**
     * URL path segments may contain "+" symbols which should not be decoded into " "
     * This method replaces "+" with %2B and delegates to URLDecoder
     * @param value value to decode
     * @return
     */
    public static String pathDecode(String value) {
        // TODO: we actually need to do a proper URI analysis here according to
        // http://tools.ietf.org/html/rfc3986
        for (int i = 0; i < RESERVED_CHARS.length; i++) {
            if (value.indexOf(RESERVED_CHARS[i]) != -1) {
                value = value.replace(RESERVED_CHARS[i], ENCODED_CHARS[i]);
            }
        }
        
        return urlDecode(value);
    }
    
}





Encode a path as required by the URL specification

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.BitSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.StringTokenizer;
/*
 Derby - Class org.apache.derby.iapi.util.PropertyUtil
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
 this work for additional information regarding copyright ownership.
 The ASF licenses this file to you under the Apache License, Version 2.0
 (the "License"); you may not use this file except in compliance with
 the License.  You may obtain a copy of the License at
 http://www.apache.org/licenses/LICENSE-2.0
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */
public class Main {

  /**
   * Array containing the safe characters set as defined by RFC 1738
   */
  private static BitSet safeCharacters;
  private static final char[] hexadecimal =
  {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
   "A", "B", "C", "D", "E", "F"};
  static {
      safeCharacters = new BitSet(256);
      int i;
      // "lowalpha" rule
      for (i = "a"; i <= "z"; i++) {
          safeCharacters.set(i);
      }
      // "hialpha" rule
      for (i = "A"; i <= "Z"; i++) {
          safeCharacters.set(i);
      }
      // "digit" rule
      for (i = "0"; i <= "9"; i++) {
          safeCharacters.set(i);
      }
      // "safe" rule
      safeCharacters.set("$");
      safeCharacters.set("-");
      safeCharacters.set("_");
      safeCharacters.set(".");
      safeCharacters.set("+");
      // "extra" rule
      safeCharacters.set("!");
      safeCharacters.set("*");
      safeCharacters.set("\"");
      safeCharacters.set("(");
      safeCharacters.set(")");
      safeCharacters.set(",");
      // special characters common to http: file: and ftp: URLs ("fsegment" and "hsegment" rules)
      safeCharacters.set("/");
      safeCharacters.set(":");
      safeCharacters.set("@");
      safeCharacters.set("&");
      safeCharacters.set("=");
  }

  /**
   * Encode a path as required by the URL specification (). This differs from <code>java.net.URLEncoder.encode()</code> which encodes according
   * to the <code>x-www-form-urlencoded</code> MIME format.
   *
   * @param path the path to encode
   * @return the encoded path
   */
  public static String encodePath(String path) {
     // stolen from org.apache.catalina.servlets.DefaultServlet ;)
      /**
       * Note: Here, " " should be encoded as "%20"
       * and "/" shouldn"t be encoded.
       */
      int maxBytesPerChar = 10;
      StringBuffer rewrittenPath = new StringBuffer(path.length());
      ByteArrayOutputStream buf = new ByteArrayOutputStream(maxBytesPerChar);
      OutputStreamWriter writer;
      try {
          writer = new OutputStreamWriter(buf, "UTF8");
      } catch (Exception e) {
          e.printStackTrace();
          writer = new OutputStreamWriter(buf);
      }
      for (int i = 0; i < path.length(); i++) {
          int c = path.charAt(i);
          if (safeCharacters.get(c)) {
              rewrittenPath.append((char)c);
          } else {
              // convert to external encoding before hex conversion
              try {
                  writer.write(c);
                  writer.flush();
              } catch(IOException e) {
                  buf.reset();
                  continue;
              }
              byte[] ba = buf.toByteArray();
              for (int j = 0; j < ba.length; j++) {
                  // Converting each byte in the buffer
                  byte toEncode = ba[j];
                  rewrittenPath.append("%");
                  int low = (toEncode & 0x0f);
                  int high = ((toEncode & 0xf0) >> 4);
                  rewrittenPath.append(hexadecimal[high]);
                  rewrittenPath.append(hexadecimal[low]);
              }
              buf.reset();
          }
      }
      return rewrittenPath.toString();
  }


}





Parse a x-www-form-urlencoded string

import java.net.URLDecoder;
import java.net.URLEncoder;
public class Main {
  public static void main(String[] argv) throws Exception {
    String line = URLEncoder.encode("name1", "UTF-8") + "=" + URLEncoder.encode("value1", "UTF-8");
    String[] pairs = line.split("\\&");
    for (int i = 0; i < pairs.length; i++) {
      String[] fields = pairs[i].split("=");
      String name = URLDecoder.decode(fields[0], "UTF-8");
      System.out.println(name);
      String value = URLDecoder.decode(fields[1], "UTF-8");
      System.out.println(value);
    }
  }
}





Provides a method to encode any string into a URL-safe form

/**
 * 
 * JFreeReport : a free Java reporting library
 * 
 *
 * Project Info:  http://reporting.pentaho.org/
 *
 * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
 *
 * This library is free software; you can redistribute it and/or modify it under the terms
 * of the GNU Lesser General Public License as published by the Free Software Foundation;
 * either version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with this
 * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
 * in the United States and other countries.]
 *
 * ------------
 * UTFEncodingUtil.java
 * ------------
 * (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
 */
import java.io.UnsupportedEncodingException;

/**
 * Provides a method to encode any string into a URL-safe form. Non-ASCII characters are first encoded as sequences of
 * two or three bytes, using the UTF-8 algorithm, before being encoded as %HH escapes.
 * <p/>
 * Code is the public example given at http://www.w3.org/International/O-URL-code.html
 *
 * @author Bert Bos
 */
public class UTFEncodingUtil
{
  /**
   * Private Constructor prevents Object Creation.
   */
  private UTFEncodingUtil()
  {
  }
  /**
   * A lookup table.
   */
  private static final String[] hex = {
      "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07",
      "%08", "%09", "%0A", "%0B", "%0C", "%0D", "%0E", "%0F",
      "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17",
      "%18", "%19", "%1A", "%1B", "%1C", "%1D", "%1E", "%1F",
      "%20", "%21", "%22", "%23", "%24", "%25", "%26", "%27",
      "%28", "%29", "%2A", "%2B", "%2C", "%2D", "%2E", "%2F",
      "%30", "%31", "%32", "%33", "%34", "%35", "%36", "%37",
      "%38", "%39", "%3A", "%3B", "%3C", "%3D", "%3E", "%3F",
      "%40", "%41", "%42", "%43", "%44", "%45", "%46", "%47",
      "%48", "%49", "%4A", "%4B", "%4C", "%4D", "%4E", "%4F",
      "%50", "%51", "%52", "%53", "%54", "%55", "%56", "%57",
      "%58", "%59", "%5A", "%5B", "%5C", "%5D", "%5E", "%5F",
      "%60", "%61", "%62", "%63", "%64", "%65", "%66", "%67",
      "%68", "%69", "%6A", "%6B", "%6C", "%6D", "%6E", "%6F",
      "%70", "%71", "%72", "%73", "%74", "%75", "%76", "%77",
      "%78", "%79", "%7A", "%7B", "%7C", "%7D", "%7E", "%7F",
      "%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87",
      "%88", "%89", "%8A", "%8B", "%8C", "%8D", "%8E", "%8F",
      "%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97",
      "%98", "%99", "%9A", "%9B", "%9C", "%9D", "%9E", "%9F",
      "%A0", "%A1", "%A2", "%A3", "%A4", "%A5", "%A6", "%A7",
      "%A8", "%A9", "%AA", "%AB", "%AC", "%AD", "%AE", "%AF",
      "%B0", "%B1", "%B2", "%B3", "%B4", "%B5", "%B6", "%B7",
      "%B8", "%B9", "%BA", "%BB", "%BC", "%BD", "%BE", "%BF",
      "%C0", "%C1", "%C2", "%C3", "%C4", "%C5", "%C6", "%C7",
      "%C8", "%C9", "%CA", "%CB", "%CC", "%CD", "%CE", "%CF",
      "%D0", "%D1", "%D2", "%D3", "%D4", "%D5", "%D6", "%D7",
      "%D8", "%D9", "%DA", "%DB", "%DC", "%DD", "%DE", "%DF",
      "%E0", "%E1", "%E2", "%E3", "%E4", "%E5", "%E6", "%E7",
      "%E8", "%E9", "%EA", "%EB", "%EC", "%ED", "%EE", "%EF",
      "%F0", "%F1", "%F2", "%F3", "%F4", "%F5", "%F6", "%F7",
      "%F8", "%F9", "%FA", "%FB", "%FC", "%FD", "%FE", "%FF"
  };
  /**
   * Encode a string according to RFC 1738.
   * <p/>
   * <quote> "...Only alphanumerics [0-9a-zA-Z], the special characters "$-_.+!*"()," [not including the quotes - ed],
   * and reserved characters used for their reserved purposes may be used unencoded within a URL."</quote>
   * <p/>
   * <ul> <li><p>The ASCII characters "a" through "z", "A" through "Z", and "0" through "9" remain the same.
   * <p/>
   * <li><p>The unreserved characters - _ . ! ~ * " ( ) remain the same.
   * <p/>
   * <li><p>All other ASCII characters are converted into the 3-character string "%xy", where xy is the two-digit
   * hexadecimal representation of the character code
   * <p/>
   * <li><p>All non-ASCII characters are encoded in two steps: first to a sequence of 2 or 3 bytes, using the UTF-8
   * algorithm; secondly each of these bytes is encoded as "%xx". </ul>
   *
   * @param s The string to be encoded
   * @return The encoded string
   */
  public static String encodeUTF8(final String s)
  {
    final StringBuffer sbuf = new StringBuffer();
    final char[] sChars = s.toCharArray();
    final int len = sChars.length;
    for (int i = 0; i < len; i++)
    {
      final int ch = sChars[i];
      if ("A" <= ch && ch <= "Z")
      {    // "A".."Z"
        sbuf.append((char) ch);
      }
      else if ("a" <= ch && ch <= "z")
      {  // "a".."z"
        sbuf.append((char) ch);
      }
      else if ("0" <= ch && ch <= "9")
      {  // "0".."9"
        sbuf.append((char) ch);
      }
      else if (ch == "-" || ch == "_"    // unreserved
          || ch == "." || ch == "!"
          || ch == "~" || ch == "*"
          || ch == "\"" || ch == "("
          || ch == ")")
      {
        sbuf.append((char) ch);
      }
      else if (ch <= 0x007f)
      {    // other ASCII
        sbuf.append(hex[ch]);
      }
      else if (ch <= 0x07FF)
      {    // non-ASCII <= 0x7FF
        sbuf.append(hex[0xc0 | (ch >> 6)]);
        sbuf.append(hex[0x80 | (ch & 0x3F)]);
      }
      else
      {          // 0x7FF < ch <= 0xFFFF
        sbuf.append(hex[0xe0 | (ch >> 12)]);
        sbuf.append(hex[0x80 | ((ch >> 6) & 0x3F)]);
        sbuf.append(hex[0x80 | (ch & 0x3F)]);
      }
    }
    return sbuf.toString();
  }
  /**
   * Encodes a byte-array. The array is expected to contain ASCII characters, or the result may not be valid.
   *
   * @param s the byte array
   * @return the array as encoded string.
   */
  private static String encodeBytes(final byte[] s)
  {
    final StringBuffer sbuf = new StringBuffer();
    final int len = s.length;
    for (int i = 0; i < len; i++)
    {
      final int ch = (s[i] & 0xff);
      if ("A" <= ch && ch <= "Z")
      {    // "A".."Z"
        sbuf.append((char) ch);
      }
      else if ("a" <= ch && ch <= "z")
      {  // "a".."z"
        sbuf.append((char) ch);
      }
      else if ("0" <= ch && ch <= "9")
      {  // "0".."9"
        sbuf.append((char) ch);
      }
      else if (ch == "-" || ch == "_"    // unreserved
          || ch == "." || ch == "!"
          || ch == "~" || ch == "*"
          || ch == "\"" || ch == "("
          || ch == ")")
      {
        sbuf.append((char) ch);
      }
      else
      {    // other ASCII
        sbuf.append(hex[ch]);
      }
    }
    return sbuf.toString();
  }
  /**
   * Encodes thh given string using the provided encoding. The encoding must be a valid Java-encoding.
   *
   * @param s        the string that should be encoded.
   * @param encoding the encoding to tranform the string into bytes.
   * @return the encoded string.
   * @throws UnsupportedEncodingException if the specified encoding is not recognized.
   */
  public static String encode(final String s, final String encoding)
      throws UnsupportedEncodingException
  {
    if ("utf-8".equalsIgnoreCase(encoding))
    {
      return encodeUTF8(s);
    }
    return encodeBytes(s.getBytes(encoding));
  }

  /**
   * Decodes the given string using the provided encoding. The encoding must be a valid
   * Java-encoding.
   *
   * @param s        the string that should be encoded.
   * @param encoding the encoding to tranform the bytes into a string.
   * @return the encoded string.
   * @throws UnsupportedEncodingException if the specified encoding is not recognized.
   */
  public static String decode(final String s, final String encoding)
      throws UnsupportedEncodingException
  {
    if ("utf-8".equalsIgnoreCase(encoding))
    {
      return decodeUTF(s);
    }
    // the resulting string will never be greater than the encoded string
    final byte[] result = new byte[s.length()];
    final char[] chars = s.toCharArray();
    int position = 0;
    for (int i = 0; i < chars.length; i++)
    {
      final char ch = chars[i];
      final int b;
      switch (ch)
      {
        case"%":
          final char lch = s.charAt(++i);
          final int hb = (Character.isDigit(lch)
              ? lch - "0"
              : 10 + Character.toLowerCase(lch) - "a") & 0xF;
          final char hch = s.charAt(++i);
          final int lb = (Character.isDigit(hch)
              ? hch - "0"
              : 10 + Character.toLowerCase(hch) - "a") & 0xF;
          b = (hb << 4) | lb;
          break;
        case"+":
          b = " ";
          break;
        default:
          b = ch;
      }
      result[position] = (byte) b;
      position += 1;
    }
    return new String(result, 0, position, encoding);
  }
  /**
   * Decodes the given string using the encoding UTF-8.
   *
   * @param s        the string that should be encoded.
   * @return the encoded string.
   */
  public static String decodeUTF(final String s)
  {
    final StringBuffer sbuf = new StringBuffer();
    final char[] chars = s.toCharArray();
    final int l = chars.length;
    int sumb = 0;
    for (int i = 0, more = -1; i < l; i++)
    {
      /* Get next byte b from URL segment s */
      final int ch = chars[i];
      final int b;
      switch (ch)
      {
        case"%":
          final char lch = s.charAt(++i);
          final int hb = (Character.isDigit(lch)
              ? lch - "0"
              : 10 + Character.toLowerCase(lch) - "a") & 0xF;
          final char hch = s.charAt(++i);
          final int lb = (Character.isDigit(hch)
              ? hch - "0"
              : 10 + Character.toLowerCase(hch) - "a") & 0xF;
          b = (hb << 4) | lb;
          break;
        case"+":
          b = " ";
          break;
        default:
          b = ch;
      }
      /* Decode byte b as UTF-8, sumb collects incomplete chars */
      if ((b & 0xc0) == 0x80)
      {      // 10xxxxxx (continuation byte)
        sumb = (sumb << 6) | (b & 0x3f);  // Add 6 bits to sumb
        if (--more == 0)
        {
          sbuf.append((char) sumb); // Add char to sbuf
        }
      }
      else if ((b & 0x80) == 0x00)
      {    // 0xxxxxxx (yields 7 bits)
        sbuf.append((char) b);      // Store in sbuf
      }
      else if ((b & 0xe0) == 0xc0)
      {    // 110xxxxx (yields 5 bits)
        sumb = b & 0x1f;
        more = 1;        // Expect 1 more byte
      }
      else if ((b & 0xf0) == 0xe0)
      {    // 1110xxxx (yields 4 bits)
        sumb = b & 0x0f;
        more = 2;        // Expect 2 more bytes
      }
      else if ((b & 0xf8) == 0xf0)
      {    // 11110xxx (yields 3 bits)
        sumb = b & 0x07;
        more = 3;        // Expect 3 more bytes
      }
      else if ((b & 0xfc) == 0xf8)
      {    // 111110xx (yields 2 bits)
        sumb = b & 0x03;
        more = 4;        // Expect 4 more bytes
      }
      else /*if ((b & 0xfe) == 0xfc)*/
      {  // 1111110x (yields 1 bit)
        sumb = b & 0x01;
        more = 5;        // Expect 5 more bytes
      }
      /* We don"t test if the UTF-8 encoding is well-formed */
    }
    return sbuf.toString();
  }
}





URL decoder

import java.net.URLDecoder;
public class MainClass {
  public static void main(String[] args) throws Exception {
    String url = "http://www.%20test.ru/";
    String decoded = URLDecoder.decode(url, "UTF-8");
    System.out.println(decoded);
  }
}



http://www. test.ru/


URLDecoder 2

import java.net.URLDecoder;
public class MainClass {
  public static void main(String[] args) {
    String input = "http://www.jexp.ru/query?pg=q&kl=XX&stype=stext&q=%2B%22Java+Programming%22&search.x=30&search.y=7";
    System.out.println(input);
    try {
      String output = URLDecoder.decode(input, "UTF8");
      System.out.println(output);
    } catch (Exception e) {
      System.err.println("Malformed URL");
    }
  }
}



http://www.jexp.ru/query?pg=q&kl=XX&stype=stext&q=%2B%22Java+Programming%22&search.x=30&search.y=7
http://www.jexp.ru/query?pg=q&kl=XX&stype=stext&q=+"Java Programming"&search.x=30&search.y=7


URLEncoder:

import java.net.URLEncoder;
public class MainClass {
  public static void main(String[] args) throws Exception {
      System.out.println(URLEncoder.encode("A%B%C", "UTF-8"));
  }
}



A%25B%25C


URLEncoder: ampersands

import java.net.URLEncoder;
public class MainClass {
  public static void main(String[] args) throws Exception {
    System.out.println(URLEncoder.encode("A&B&C&D", "UTF-8"));
  }
}



A%26B%26C%26D


URLEncoder: asterisks

import java.net.URLEncoder;
public class MainClass {
  public static void main(String[] args) throws Exception {
    System.out.println(URLEncoder.encode("A*B*C", "UTF-8"));
  }
}



A*B*C


URLEncoder: colons(:)

import java.net.URLEncoder;
public class MainClass {
  public static void main(String[] args) throws Exception {
    System.out.println(URLEncoder.encode("A:B:C:D", "UTF-8"));
  }
}



A%3AB%3AC%3AD


URLEncoder: dot

import java.net.URLEncoder;
public class MainClass {
  public static void main(String[] args) throws Exception {
    System.out.println(URLEncoder.encode("A.B.C.E", "UTF-8"));
  }
}



A%28B%29C%28D%29


URLEncoder: equal sign

import java.net.URLEncoder;
public class MainClass {
  public static void main(String[] args) throws Exception {
    System.out.println(URLEncoder.encode("A=B=C=D=E", "UTF-8"));
  }
}



A%3DB%3DC%3DD%3DE


URLEncoder: parentheses()

import java.net.URLEncoder;
public class MainClass {
  public static void main(String[] args) throws Exception {
    System.out.println(URLEncoder.encode("A(B)C(D)", "UTF-8"));
  }
}





URLEncoder: plus sign

import java.net.URLEncoder;
public class MainClass {
  public static void main(String[] args) throws Exception {
    System.out.println(URLEncoder.encode("A+B+C", "UTF-8"));
  }
}



A%2BB%2BC


URLEncoder: quotations

import java.net.URLEncoder;
public class MainClass {
  public static void main(String[] args) throws Exception {
    System.out.println(URLEncoder.encode("A\"B\"C\"D\"E", "UTF-8"));
  }
}



A%22B%22C%22D%22E


URLEncoder: slashes

import java.net.URLEncoder;
public class MainClass {
  public static void main(String[] args) throws Exception {
    System.out.println(URLEncoder.encode("A/B/C/", "UTF-8"));
  }
}



A%2FB%2FC%2F


URLEncoder: space

import java.net.URLEncoder;
public class MainClass {
  public static void main(String[] args) throws Exception {
    System.out.println(URLEncoder.encode("A B C", "UTF-8"));
  }
}



A+B+C


URLEncoder: tildes(~)

import java.net.URLEncoder;
public class MainClass {
  public static void main(String[] args) throws Exception {
    System.out.println(URLEncoder.encode("A~B~C~D", "UTF-8"));
  }
}



A%7EB%7EC%7ED


URL encoding

/*
    JSPWiki - a JSP-based WikiWiki clone.
    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    with the License.  You may obtain a copy of the License at
       http://www.apache.org/licenses/LICENSE-2.0
    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    KIND, either express or implied.  See the License for the
    specific language governing permissions and limitations
    under the License.    
 */
import java.io.UnsupportedEncodingException;
import java.security.SecureRandom;
import java.util.Properties;
import java.util.Random;

/**
 *  Contains a number of static utility methods.
 */
// FIXME3.0: Move to the "util" package
public final class TextUtil
{
    static final String   HEX_DIGITS = "0123456789ABCDEF";
    /**
     *  Private constructor prevents instantiation.
     */
    private TextUtil()
    {}
    
    /**
     *  java.net.URLEncoder.encode() method in JDK < 1.4 is buggy.  This duplicates
     *  its functionality.
     *  @param rs the string to encode
     *  @return the URL-encoded string
     */
    protected static String urlEncode( byte[] rs )
    {
        StringBuffer result = new StringBuffer(rs.length*2);
        // Does the URLEncoding.  We could use the java.net one, but
        // it does not eat byte[]s.
        for( int i = 0; i < rs.length; i++ )
        {
            char c = (char) rs[i];
            switch( c )
            {
              case "_":
              case ".":
              case "*":
              case "-":
              case "/":
                result.append( c );
                break;
              case " ":
                result.append( "+" );
                break;
              default:
                if( (c >= "a" && c <= "z") ||
                    (c >= "A" && c <= "Z") ||
                    (c >= "0" && c <= "9") )
                {
                    result.append( c );
                }
                else
                {
                    result.append( "%" );
                    result.append( HEX_DIGITS.charAt( (c & 0xF0) >> 4 ) );
                    result.append( HEX_DIGITS.charAt( c & 0x0F ) );
                }
            }
        } // for
        return result.toString();
    }
    /**
     *  URL encoder does not handle all characters correctly.
     *  See  for more information.
     *  <P>
     *  Thanks to CJB for this fix.
     *  
     *  @param bytes The byte array containing the bytes of the string
     *  @param encoding The encoding in which the string should be interpreted
     *  @return A decoded String
     *  
     *  @throws UnsupportedEncodingException If the encoding is unknown.
     *  @throws IllegalArgumentException If the byte array is not a valid string.
     */
    protected static String urlDecode( byte[] bytes, String encoding )
        throws UnsupportedEncodingException,
               IllegalArgumentException
    {
        if(bytes == null)
        {
            return null;
        }
        byte[] decodeBytes   = new byte[bytes.length];
        int decodedByteCount = 0;
        try
        {
            for( int count = 0; count < bytes.length; count++ )
            {
                switch( bytes[count] )
                {
                  case "+":
                    decodeBytes[decodedByteCount++] = (byte) " ";
                    break ;
                  case "%":
                    decodeBytes[decodedByteCount++] = (byte)((HEX_DIGITS.indexOf(bytes[++count]) << 4) +
                                                             (HEX_DIGITS.indexOf(bytes[++count])) );
                    break ;
                  default:
                    decodeBytes[decodedByteCount++] = bytes[count] ;
                }
            }
        }
        catch (IndexOutOfBoundsException ae)
        {
            throw new IllegalArgumentException( "Malformed UTF-8 string?" );
        }
        String processedPageName = null ;
        try
        {
            processedPageName = new String(decodeBytes, 0, decodedByteCount, encoding) ;
        }
        catch (UnsupportedEncodingException e)
        {
            throw new UnsupportedEncodingException( "UTF-8 encoding not supported on this platform" );
        }
        return processedPageName;
    }
    /**
     *  As java.net.URLEncoder class, but this does it in UTF8 character set.
     *  
     *  @param text The text to decode
     *  @return An URLEncoded string.
     */
    public static String urlEncodeUTF8( String text )
    {
        // If text is null, just return an empty string
        if ( text == null )
        {
            return "";
        }
        byte[] rs;
        try
        {
            rs = text.getBytes("UTF-8");
            return urlEncode( rs );
        }
        catch( UnsupportedEncodingException e )
        {
            throw new Exception("UTF-8 not supported!?!");
        }
    }
    /**
     *  As java.net.URLDecoder class, but for UTF-8 strings.  null is a safe
     *  value and returns null.
     *  
     *  @param utf8 The UTF-8 encoded string
     *  @return A plain, normal string.
     */
    public static String urlDecodeUTF8( String utf8 )
    {
        String rs = null;
        if( utf8 == null ) return null;
        try
        {
            rs = urlDecode( utf8.getBytes("ISO-8859-1"), "UTF-8" );
        }
        catch( UnsupportedEncodingException e )
        {
            throw new Exception("UTF-8 or ISO-8859-1 not supported!?!");
        }
        return rs;
    }
    /**
     * Provides encoded version of string depending on encoding.
     * Encoding may be UTF-8 or ISO-8859-1 (default).
     *
     * <p>This implementation is the same as in
     * FileSystemProvider.mangleName().
     * 
     * @param data A string to encode
     * @param encoding The encoding in which to encode
     * @return An URL encoded string.
     */
    public static String urlEncode( String data, String encoding )
    {
        // Presumably, the same caveats apply as in FileSystemProvider.
        // Don"t see why it would be horribly kludgy, though.
        if( "UTF-8".equals( encoding ) )
        {
            return TextUtil.urlEncodeUTF8( data );
        }
        try
        {
            return TextUtil.urlEncode( data.getBytes(encoding) );
        }
        catch (UnsupportedEncodingException uee)
        {
            throw new Exception("Could not encode String into" + encoding);
        }
    }
    /**
     * Provides decoded version of string depending on encoding.
     * Encoding may be UTF-8 or ISO-8859-1 (default).
     *
     * <p>This implementation is the same as in
     * FileSystemProvider.unmangleName().
     * 
     * @param data The URL-encoded string to decode
     * @param encoding The encoding to use
     * @return A decoded string.
     * @throws UnsupportedEncodingException If the encoding is unknown
     * @throws IllegalArgumentException If the data cannot be decoded.
     */
    public static String urlDecode( String data, String encoding )
        throws UnsupportedEncodingException,
               IllegalArgumentException
    {
        // Presumably, the same caveats apply as in FileSystemProvider.
        // Don"t see why it would be horribly kludgy, though.
        if( "UTF-8".equals( encoding ) )
        {
            return TextUtil.urlDecodeUTF8( data );
        }
        try
        {
            return TextUtil.urlDecode( data.getBytes(encoding), encoding );
        }
        catch (UnsupportedEncodingException uee)
        {
            throw new Exception("Could not decode String into" + encoding);
        }
    }
}