104 votes

Équivalent Java du composant encodeURIComponent de JavaScript produisant une sortie identique?

J'ai fait des expériences avec différents morceaux de code Java essayer de venir avec quelque chose qui va coder une chaîne de caractères contenant des citations, des espaces et des "exotiques" des caractères Unicode et produire une sortie identique à du JavaScript encodeURIComponent fonction.

Mon torture chaîne de test est: "Un" B ± "

Si j'entre le code JavaScript suivant déclaration dans Firebug:

encodeURIComponent('"A" B ± "');

—Puis-je obtenir:

"%22A%22%20B%20%C2%B1%20%22"

Voici mon petit test de programme Java:

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

public class EncodingTest
{
  public static void main(String[] args) throws UnsupportedEncodingException
  {
    String s = "\"A\" B ± \"";
    System.out.println("URLEncoder.encode returns "
      + URLEncoder.encode(s, "UTF-8"));

    System.out.println("getBytes returns "
      + new String(s.getBytes("UTF-8"), "ISO-8859-1"));
  }
}

—Sortie de ce programme:

URLEncoder.encoder les retours %22%22+B+%C2%B1+%22
getBytes renvoie "A" B ± "

À proximité, mais pas de cigare! Quelle est la meilleure façon de l'encodage d'une chaîne UTF-8 à l'aide de Java, de sorte qu'elle produit le même résultat que du JavaScript encodeURIComponent?

EDIT: je suis en utilisant Java 1.4 passer à Java 5 peu de temps.

126voto

John Topley Points 58789

C’est le cours que j’ai eu à la fin:

 import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

/**
 * Utility class for JavaScript compatible UTF-8 encoding and decoding.
 * 
 * @see http://stackoverflow.com/questions/607176/java-equivalent-to-javascripts-encodeuricomponent-that-produces-identical-output
 * @author John Topley 
 */
public class EncodingUtil
{
  /**
   * Decodes the passed UTF-8 String using an algorithm that's compatible with
   * JavaScript's <code>decodeURIComponent</code> function. Returns
   * <code>null</code> if the String is <code>null</code>.
   *
   * @param s The UTF-8 encoded String to be decoded
   * @return the decoded String
   */
  public static String decodeURIComponent(String s)
  {
    if (s == null)
    {
      return null;
    }

    String result = null;

    try
    {
      result = URLDecoder.decode(s, "UTF-8");
    }

    // This exception should never occur.
    catch (UnsupportedEncodingException e)
    {
      result = s;  
    }

    return result;
  }

  /**
   * Encodes the passed String as UTF-8 using an algorithm that's compatible
   * with JavaScript's <code>encodeURIComponent</code> function. Returns
   * <code>null</code> if the String is <code>null</code>.
   * 
   * @param s The String to be encoded
   * @return the encoded String
   */
  public static String encodeURIComponent(String s)
  {
    String result = null;

    try
    {
      result = URLEncoder.encode(s, "UTF-8")
                         .replaceAll("\\+", "%20")
                         .replaceAll("\\%21", "!")
                         .replaceAll("\\%27", "'")
                         .replaceAll("\\%28", "(")
                         .replaceAll("\\%29", ")")
                         .replaceAll("\\%7E", "~");
    }

    // This exception should never occur.
    catch (UnsupportedEncodingException e)
    {
      result = s;
    }

    return result;
  }  

  /**
   * Private constructor to prevent this class from being instantiated.
   */
  private EncodingUtil()
  {
    super();
  }
}
 

69voto

Tomalak Points 150423

À la recherche à la mise en œuvre des différences, je vois que:

MDC sur encodeURIComponent():

  • caractères littéraux (regex représentation): [-a-zA-Z0-9._*~'()!]

Java 1.5.0 documentation sur URLEncoder:

  • caractères littéraux (regex représentation): [-a-zA-Z0-9._*]
  • le caractère espace, " " est converti en un signe plus, en "+".

Donc en gros, pour obtenir le résultat souhaité, utilisez URLEncoder.encode(s, "UTF-8") et puis faire un peu de post-traitement:

  • remplacer toutes les occurrences de "+" avec "%20"
  • remplacer toutes les occurrences de "%xx" qui représente tout de [~'()!] de retour à leur littérale, par contre

16voto

Ravi Wallau Points 5012

Utilisation du moteur javascript fourni avec Java 6:



import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class Wow
{
    public static void main(String[] args) throws Exception
    {
        ScriptEngineManager factory = new ScriptEngineManager();
        ScriptEngine engine = factory.getEngineByName("JavaScript");
        engine.eval("print(encodeURIComponent('\"A\" B ± \"'))");
    }
}
 

Rendement:% 22A% 22% 20B% 20% c2% b1% 20% 22

Le cas est différent mais c'est plus proche de ce que vous voulez.

5voto

Joe Mill Points 31

Je suis venu avec ma propre version de la encodeURIComponent, parce que la solution affichée a un problème, s'il y avait un + présent dans la chaîne, qui devrait être encodé, il sera converti en un espace.

Alors voici ma classe:

 import java.io.UnsupportedEncodingException;
import java.util.BitSet;

public final class EscapeUtils
{
    /** used for the encodeURIComponent function */
    private static final BitSet dontNeedEncoding;

    static
    {
        dontNeedEncoding = new BitSet(256);

        // a-z
        for (int i = 97; i <= 122; ++i)
        {
            dontNeedEncoding.set(i);
        }
        // A-Z
        for (int i = 65; i <= 90; ++i)
        {
            dontNeedEncoding.set(i);
        }
        // 0-9
        for (int i = 48; i <= 57; ++i)
        {
            dontNeedEncoding.set(i);
        }

        // '()*
        for (int i = 39; i <= 42; ++i)
        {
            dontNeedEncoding.set(i);
        }
        dontNeedEncoding.set(33); // !
        dontNeedEncoding.set(45); // -
        dontNeedEncoding.set(46); // .
        dontNeedEncoding.set(95); // _
        dontNeedEncoding.set(126); // ~
    }

    /**
     * A Utility class should not be instantiated.
     */
    private EscapeUtils()
    {

    }

    /**
     * Escapes all characters except the following: alphabetic, decimal digits, - _ . ! ~ * ' ( )
     * 
     * @param input
     *            A component of a URI
     * @return the escaped URI component
     */
    public static String encodeURIComponent(String input)
    {
        if (input == null)
        {
            return input;
        }

        StringBuilder filtered = new StringBuilder(input.length());
        char c;
        for (int i = 0; i < input.length(); ++i)
        {
            c = input.charAt(i);
            if (dontNeedEncoding.get(c))
            {
                filtered.append(c);
            }
            else
            {
                final byte[] b = charToBytesUTF(c);

                for (int j = 0; j < b.length; ++j)
                {
                    filtered.append('%');
                    filtered.append("0123456789ABCDEF".charAt(b[j] >> 4 & 0xF));
                    filtered.append("0123456789ABCDEF".charAt(b[j] & 0xF));
                }
            }
        }
        return filtered.toString();
    }

    private static byte[] charToBytesUTF(char c)
    {
        try
        {
            return new String(new char[] { c }).getBytes("UTF-8");
        }
        catch (UnsupportedEncodingException e)
        {
            return new byte[] { (byte) c };
        }
    }
}
 

3voto

sangupta Points 1489

J'ai proposé une autre implémentation documentée à l' adresse http://blog.sangupta.com/2010/05/encodeuricomponent-and.html . L'implémentation peut également gérer les octets Unicode.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X