Android: ¿cómo analizar URL String con espacios al objeto URI?

Tengo una cadena que representa una URL que contiene espacios y quiero convertirla en un objeto URI. Si es simple intenta hacer

String myString = "http://myhost.com/media/mp3s/9/Agenda of swine - 13. Persecution Ascension_ leave nothing standing.mp3"; URI myUri = new URI(myString); 

me da

 java.net.URISyntaxException: Illegal character in path at index X 

donde el índice X es la posición del primer espacio en la cadena URL.

¿Cómo puedo analizar myString en un objeto URI ?

De hecho, debería URI-codificar los caracteres “inválidos”. Dado que la cadena en realidad contiene la URL completa, es difícil codificarla URI correctamente. Usted no sabe qué diagonales / deberían tenerse en cuenta y cuáles no. No puede predecir eso en una String procesar de antemano. El problema realmente necesita ser resuelto en un nivel superior. ¿De dónde viene esa String ? ¿Está codificado? Entonces simplemente cámbialo tú mismo en consecuencia. ¿Entra como entrada del usuario? Validarlo y mostrar el error, deja que el usuario se resuelva solo.

En cualquier caso, si puede asegurarse de que solo son los espacios en las URL lo que lo hace inválido, entonces también puede hacer una cadena por cadena reemplazar con %20 :

 URI uri = new URI(string.replace(" ", "%20")); 

O bien, si puede asegurarse de que sea solo la parte posterior a la última barra que necesita ser codificada por URI, entonces también puede hacerlo con la ayuda de la clase de utilidad android.net.Uri :

 int pos = string.lastIndexOf('/') + 1; URI uri = new URI(string.substring(0, pos) + Uri.encode(string.substring(pos))); 

Tenga en cuenta que URLEncoder es apto para la tarea, ya que está diseñado para codificar los nombres / valores de los parámetros de cadena de consulta application/x-www-form-urlencoded reglas application/x-www-form-urlencoded (como se usan en los formularios HTML). Consulte también la encoding URL de Java de los parámetros de cadena de consulta .

 java.net.URLEncoder.encode(finalPartOfString, "utf-8"); 

Esto codificará URL de la cadena.

finalPartOfString es la parte posterior a la última barra: en su caso, el nombre de la canción, como parece.

Para manejar espacios, @ y otros caracteres inseguros en ubicaciones arbitrarias en la ruta de la url, use Uri.Builder en combinación con una instancia local de URL como he descrito aquí :

 private Uri.Builder builder; public Uri getUriFromUrl(String thisUrl) { URL url = new URL(thisUrl); builder = new Uri.Builder() .scheme(url.getProtocol()) .authority(url.getAuthority()) .appendPath(url.getPath()); return builder.build(); } 
 URL url = Test.class.getResource(args[0]); // reading demo file path from // same location where class File input=null; try { input = new File(url.toURI()); } catch (URISyntaxException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } 

Escribí esta función:

 public static String encode(@NonNull String uriString) { if (TextUtils.isEmpty(uriString)) { Assert.fail("Uri string cannot be empty!"); return uriString; } // getQueryParameterNames is not exist then cannot iterate on queries if (Build.VERSION.SDK_INT < 11) { return uriString; } // Check if uri has valid characters // See https://tools.ietf.org/html/rfc3986 Pattern allowedUrlCharacters = Pattern.compile("([A-Za-z0-9_.~:/?\\#\\[\\]@!$&'()*+,;" + "=-]|%[0-9a-fA-F]{2})+"); Matcher matcher = allowedUrlCharacters.matcher(uriString); String validUri = null; if (matcher.find()) { validUri = matcher.group(); } if (TextUtils.isEmpty(validUri) || uriString.length() == validUri.length()) { return uriString; } // The uriString is not encoded. Then recreate the uri and encode it this time Uri uri = Uri.parse(uriString); Uri.Builder uriBuilder = new Uri.Builder() .scheme(uri.getScheme()) .authority(uri.getAuthority()); for (String path : uri.getPathSegments()) { uriBuilder.appendPath(path); } for (String key : uri.getQueryParameterNames()) { uriBuilder.appendQueryParameter(key, uri.getQueryParameter(key)); } String correctUrl = uriBuilder.build().toString(); return correctUrl; }