2010-04-13 10 views
20

Necesito decodificar un URI que contiene una cadena de consulta; comportamiento de la entrada/salida esperada es algo como lo siguiente:Cadena de consulta URI de decodificación en Java

abstract class URIParser 
{  
    /** example input: 
     * something?alias=pos&FirstName=Foo+A%26B%3DC&LastName=Bar */ 
    URIParser(String input) { ... } 
    /** should return "something" for the example input */ 
    public String getPath(); 
    /** should return a map 
     * {alias: "pos", FirstName: "Foo+A&B=C", LastName: "Bar"} */ 
    public Map<String,String> getQuery(); 
} 

He intentado usar java.net.URI, pero parece que para decodificar la cadena de consulta por lo que en el ejemplo anterior me quedo con "alias = pos & Nombre = Foo + A & B = C & LastName = Barra "entonces hay ambigüedad si un" & "es un separador de consulta o es un caracter en un componente de consulta.

Editar: que acaba de intentar URI.getRawQuery() y no lo hace la codificación, por lo que se puede dividir la cadena de consulta con un &, pero entonces ¿qué hago? Javascript tiene decodeURIComponent, parece que no puedo encontrar el método correspondiente en Java.

¿Alguna sugerencia? Preferiría no usar ninguna biblioteca nueva.

+0

Dado que no desea para introducir nuevas bibliotecas, ¿puedo preguntar en qué entorno recibe estas URI? – stacker

Respuesta

15

Véase la clase URLDecoder

+4

Debe tenerse en cuenta que debe identificar la parte de consulta y dividir los parámetros en pares clave/valor antes de usar esto, pero decodificará los valores porcentuales codificados a la codificación dada (consulte UTF-8) de acuerdo con el HTML ' aplicación/x-www-form-urlencoded' spec. – McDowell

53

Uso

URLDecoder.decode(proxyRequestParam.replace("+", "%2B"), "UTF-8") 
      .replace("%2B", "+") 

para simular decodeURIComponent. El URLDecoder de Java decodifica el signo más en un espacio, que no es lo que desea, por lo tanto, necesita las instrucciones de reemplazo.

Advertencia: la .replace("%2B", "+") al final se corromperán datos si el original (pre-x-www-form-urlencoded) contenía esa cadena, como @xehpuk señaló.

+3

Esta debería ser la respuesta aceptada. Los URI tratan el símbolo + como está, mientras que los espacios están codificados en% 20. URLDecoder no es compatible con cadenas codificadas URI ya que decodificará tanto + como% 20 en un espacio. – Kosta

+3

¿Cuál es el punto de la segunda sustitución? Después de la decodificación, ya no habrá instancias de "% 2B" en la cadena, ya que todas se reemplazarán por "+", por lo que no habrá nada para que el reemplazo coincida. –

+2

El punto es que no quiere caracteres codificados en una cadena decodificada. Como Java no decodifica el + -sign como JavaScript, primero codifico el + -sign para que no sea tocado por Java y luego decodifique el% 2B en + -sign. En resumen: si no hiciera esto, la URL descodificada no contendría los signos + originales (ya que Java los habría perdido en la fase de decodificación). – janb

0

cuanto a la cuestión con el signo +:

Hice una clase de ayuda que envuelve la función URLDecoder basado en la respuesta de @janb

import android.net.Uri; 
import android.support.annotation.Nullable; 
import android.text.TextUtils; 

import java.io.UnsupportedEncodingException; 
import java.net.URLDecoder; 
import java.text.SimpleDateFormat; 
import java.util.Date; 
import java.util.Locale; 

public class DateDecoder { 

    private static final String KEY_DATE = "datekey"; 

    private static final SimpleDateFormat SIMPLE_DATE_FORMAT = 
      new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZZZ", Locale.US); 


    public static void main(String[] args) throws UnsupportedEncodingException { 
     try { 
      Uri uri = Uri.parse("http://asdf.com?something=12345&" + 
        KEY_DATE +"=2016-12-24T12:00:00+01:00"); 

      System.out.println("parsed date: " + DateDecoder.createDate(uri)); // parsed date: Sat Dec 24 12:00:00 GMT+01:00 2016 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    @Nullable 
    public static Date createDate(@Nullable Uri data) { 
     if (data != null) { 
      try { 
       String withPlus = decodeButKeepPlus(KEY_DATE, data.getEncodedQuery()); 
       if (!TextUtils.isEmpty(withPlus)) { 
        return SIMPLE_DATE_FORMAT.parse(withPlus); 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
     return null; 
    } 

    /** 
    * copied from android.net.Uri.java 
    */ 
    @Nullable 
    public static String decodeButKeepPlus(String encodedKey, String completeEncodedQuery) 
      throws UnsupportedEncodingException { 

     final int length = completeEncodedQuery.length(); 
     int start = 0; 
     do { 
      int nextAmpersand = completeEncodedQuery.indexOf('&', start); 
      int end = nextAmpersand != -1 ? nextAmpersand : length; 

      int separator = completeEncodedQuery.indexOf('=', start); 
      if (separator > end || separator == -1) { 
       separator = end; 
      } 

      if (separator - start == encodedKey.length() 
        && completeEncodedQuery.regionMatches(start, encodedKey, 0, encodedKey.length())) { 
       if (separator == end) { 
        return ""; 
       } else { 
        String encodedValue = completeEncodedQuery.substring(separator + 1, end); 
        if (!TextUtils.isEmpty(encodedValue)) { 
         return URLDecoder.decode(encodedValue.replace("+", "%2B"), "UTF-8").replace("%2B", "+"); 
        } 
       } 
      } 

      // Move start to end of name. 
      if (nextAmpersand != -1) { 
       start = nextAmpersand + 1; 
      } else { 
       break; 
      } 
     } while (true); 
     return null; 
    } 

} 
1
var reqParam = URLDecoder.decode(reqParam, "UTF-8") 
Cuestiones relacionadas