2010-04-07 110 views
56

我有一个字符串表示一个包含空格的URL,并希望将其转换为一个URI对象。如果是尝试简单的事情Android:howto解析URL字符串与URI对象的空格?

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

它给了我

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

其中指数X是在URL字符串的第一个空间的位置。

如何可以解析myStringURI对象?

回答

110

你其实应该URI-encode“无效”字。由于字符串实际上包含完整的URL,因此很难对其进行正确的URI编码。您不知道应该将哪些斜杠/考虑在内,哪些不适用。您无法事先预测原始String。这个问题真的需要在更高的层面上解决。 String从哪里来?它是否被硬编码?然后,只需相应地改变它。它是否以用户输入的形式出现?验证并显示错误,让用户自行解决。

在任何方式,如果你能保证它是只有在URL中的空间,这使得它无效,那么你也可以只是做一个字符串逐串%20替换:

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

int pos = string.lastIndexOf('/') + 1; 
URI uri = new URI(string.substring(0, pos) + Uri.encode(string.substring(pos))); 
:或者,如果你能保证它的唯一 其中需要被URI编码的最后一个斜线之后的部分,那么你也可以只是 android.net.Uri实用类的帮助,这样做

请注意URLEncoder是不适合的任务,因为它被设计为按照application/x-www-form-urlencoded规则(如在HTML表单中使用的)对查询字符串参数名称/值进行编码。另见Java URL encoding of query string parameters

+1

用'%20'代替空格就是诀窍。 THX – Mannaz 2010-04-07 15:14:38

+4

@Mannaz - 当歌曲名称中出现另一个“无效”符号时要小心。 – Bozho 2010-04-07 19:31:02

+0

@BalusC我试过URLEncoder.encode(“查询字符串”,“UTF-8”);它返回+符号像这样“查询+字符串”,我期待“%20”。所以我用string.replace和硬编码的值。解决了这个问题。谢谢(你的)信息。有没有其他的途径来编码,而不是手动替换..? – praveenb 2012-04-05 11:20:56

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

这将是URL-encode的字符串。

finalPartOfString是最后一个斜线之后的部分 - 在你的情况下,歌曲的名字,因为它似乎。

+2

它也将urlencode冒号和斜线,这将导致url仍然无效。他基本上只需要对空格进行urlencode以使其有效。 – BalusC 2010-04-07 14:26:32

+0

@BalusC,谢谢,我添加了一个更新。 – Bozho 2010-04-07 14:29:25

+0

好了,这让我在'URISyntaxException'但现在我从服务器获取404。 的网址我得到的是通过'http://myhost.com/media/mp3s/9/Agenda+of+swine + - + 13 +迫害+ Ascension_ +留下+什么+ standing.mp3'。 我使用URI在'org.apache.http.client.methods.HttpGet。HttpGet'请求。有任何想法吗? – Mannaz 2010-04-07 14:44:16

1

要处理空格,@,并在URL路径的任意位置等不安全字符,请使用Uri.Builder与URL的本地实例组合我所描述here

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(); 
} 
0
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(); 
} 
+0

负号为什么是负号? – siddmuk2005 2014-08-04 10:26:45

+0

,因为这不回答这个问题。 – MetaFight 2014-09-02 15:56:09

+1

我已经给这个从URL中删除的空间,所以它解决了我的问题,因为当阅读文件位置FileInputStream指向空,而阅读与空它会抛出异常BU使用URI我没有得到问题。 – siddmuk2005 2014-09-04 06:07:44

0

我写了这个函数:

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; 
}