Java 在 Android 上解析查询字符串

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1667278/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 18:55:57  来源:igfitidea点击:

Parsing query strings on Android

javaandroidparsingurl

提问by Will

Java EE has ServletRequest.getParameterValues().

Java EE 有ServletRequest.getParameterValues()

On non-EE platforms, URL.getQuery()simply returns a string.

在非 EE 平台上,URL.getQuery()只返回一个字符串。

What's the normal way to properly parse the query string in a URL when noton Java EE?

不在Java EE 上时,正确解析 URL 中的查询字符串的正常方法是什么?



<rant>

<咆哮>

It is popular in the answers to try and make your own parser. This is very interesting and exciting micro-coding project, but I cannot say that it is a good idea:(

在尝试制作自己的解析器的答案中很受欢迎。这是一个非常有趣和令人兴奋的微编码项目,但我不能说这是一个好主意:(

The code snippets below are generally flawed or broken, btw. Breaking them is an interesting exercise for the reader. And to the hackers attacking the websites that use them.

下面的代码片段通常有缺陷或损坏,顺便说一句。打破它们对读者来说是一个有趣的练习。 以及攻击使用它们的网站的黑客

Parsing query strings is a well defined problem but reading the spec and understanding the nuances is non-trivial. It is far better to let some platform library coder do the hard work, and do the fixing, for you!

解析查询字符串是一个定义明确的问题,但阅读规范并理解细微差别并非易事。让一些平台库编码器为您完成艰苦的工作并进行修复要好得多!

</rant>

< /咆哮>

采纳答案by Nick Fortescue

Since Android M things have got more complicated. The answer of android.net.URI.getQueryParameter() has a bug which breaks spaces before JellyBean. Apache URLEncodedUtils.parse()worked, but was deprecated in L, and removed in M.

由于 Android M 事情变得更加复杂。android.net.URI.getQueryParameter()的答案有一个错误,它在 JellyBean 之前破坏了空格。 Apache URLEncodedUtils.parse()有效,但在 L已弃用,并在 M 中删除

So the best answer now is UrlQuerySanitizer. This has existed since API level 1 and still exists. It also makes you think about the tricky issues like how do you handle special characters, or repeated values.

所以现在最好的答案是UrlQuerySanitizer。这从 API 级别 1 开始就存在并且仍然存在。它还让您思考棘手的问题,例如如何处理特殊字符或重复值。

The simplest code is

最简单的代码是

UrlQuerySanitizer.ValueSanitizer sanitizer = UrlQuerySanitizer.getAllButNullLegal();
// remember to decide if you want the first or last parameter with the same name
// If you want the first call setPreferFirstRepeatedParameter(true);
sanitizer.parseUrl(url);
String value = sanitizer.getValue("paramname"); // get your value

回答by ChadNC

For a servlet or a JSP page you can get querystring key/value pairs by using request.getParameter("paramname")

对于 servlet 或 JSP 页面,您可以使用 request.getParameter("paramname") 获取查询字符串键/值对

String name = request.getParameter("name");

There are other ways of doing it but that's the way I do it in all the servlets and jsp pages that I create.

还有其他方法可以做到这一点,但这就是我在我创建的所有 servlet 和 jsp 页面中的做法。

回答by Jay

You say "Java" but "not Java EE". Do you mean you are using JSP and/or servlets but not a full Java EE stack? If that's the case, then you should still have request.getParameter() available to you.

您说“Java”但“不是 Java EE”。您的意思是您使用的是 JSP 和/或 servlet 而不是完整的 Java EE 堆栈?如果是这种情况,那么您应该仍然可以使用 request.getParameter() 。

If you mean you are writing Java but you are not writing JSPs nor servlets, or that you're just using Java as your reference point but you're on some other platform that doesn't have built-in parameter parsing ... Wow, that just sounds like an unlikely question, but if so, the principle would be:

如果您的意思是您正在编写 Java 但您没有编写 JSP 或 servlet,或者您只是使用 Java 作为您的参考点,但您在其他一些没有内置参数解析的平台上......哇,这听起来像是一个不太可能的问题,但如果是这样,原则将是:

xparm=0
word=""
loop
  get next char
  if no char
    exit loop
  if char=='='
    param_name[xparm]=word
    word=""
  else if char=='&'
    param_value[xparm]=word
    word=""
    xparm=xparm+1
  else if char=='%'
    read next two chars
    word=word+interpret the chars as hex digits to make a byte
  else
    word=word+char

(I could write Java code but that would be pointless, because if you have Java available, you can just use request.getParameters.)

(我可以编写 Java 代码,但这毫无意义,因为如果您有可用的 Java,则只需使用 request.getParameters。)

回答by u7867

Parsing the query string is a bit more complicated than it seems, depending on how forgiving you want to be.

解析查询字符串比看起来要复杂一些,这取决于您想要的宽容程度。

First, the query string is ascii bytes. You read in these bytes one at a time and convert them to characters. If the character is ? or & then it signals the start of a parameter name. If the character is = then it signals the start of a paramter value. If the character is % then it signals the start of an encoded byte. Here is where it gets tricky.

首先,查询字符串是 ascii 字节。您一次一个地读入这些字节并将它们转换为字符。如果字符是 ? 或 & 然后它表示参数名称的开始。如果字符是 = 那么它表示参数值的开始。如果字符是 % 则它表示编码字节的开始。这就是它变得棘手的地方。

When you read in a % char you have to read the next two bytes and interpret them as hex digits. That means the next two bytes will be 0-9, a-f or A-F. Glue these two hex digits together to get your byte value. But remember, bytes are not characters. You have to know what encoding was used to encode the characters. The character é does not encode the same in UTF-8 as it does in ISO-8859-1. In general it's impossible to know what encoding was used for a given character set. I always use UTF-8 because my web site is configured to always serve everything using UTF-8 but in practice you can't be certain. Some user-agents will tell you the character encoding in the request; you can try to read that if you have a full HTTP request. If you just have a url in isolation, good luck.

当您读入 % char 时,您必须读取接下来的两个字节并将它们解释为十六进制数字。这意味着接下来的两个字节将是 0-9,af 或 AF。将这两个十六进制数字粘在一起以获得您的字节值。但请记住,字节不是字符。您必须知道使用什么编码对字符进行编码。字符 é 在 UTF-8 中的编码方式与 ISO-8859-1 中的不同。一般来说,不可能知道给定字符集使用了什么编码。我总是使用 UTF-8,因为我的网站配置为始终使用 UTF-8 提供所有内容,但实际上您无法确定。一些用户代理会告诉你请求中的字符编码;如果您有完整的 HTTP 请求,您可以尝试阅读该内容。如果您只有一个单独的 url,祝您好运。

Anyway, assuming you are using UTF-8 or some other multi-byte character encoding, now that you've decoded one encoded byte you have to set it aside until you capture the next byte. You need all the encoded bytes that are together because you can't url-decode properly one byte at a time. Set aside all the bytes that are together then decode them all at once to reconstruct your character.

无论如何,假设您使用的是 UTF-8 或其他一些多字节字符编码,既然您已经解码了一个编码字节,您必须将其放在一边,直到您捕获下一个字节。您需要将所有编码的字节放在一起,因为您无法一次正确地对一个字节进行 url 解码。将所有在一起的字节放在一边,然后一次解码它们以重建你的角色。

Plus it gets more fun if you want to be lenient and account for user-agents that mangle urls. For example, some webmail clients double-encode things. Or double up the ?&= chars (for example: http://yoursite.com/blah??p1==v1&&p2==v2). If you want to try to gracefully deal with this, you will need to add more logic to your parser.

此外,如果您想宽容一点并考虑破坏网址的用户代理,它会变得更有趣。例如,一些网络邮件客户端对事物进行双重编码。或者将 ?&= 字符加倍(例如:) http://yoursite.com/blah??p1==v1&&p2==v2。如果您想尝试优雅地处理此问题,则需要向解析器添加更多逻辑。

回答by ZZ Coder

I don't think there is one in JRE. You can find similar functions in other packages like Apache HttpClient. If you don't use any other packages, you just have to write your own. It's not that hard. Here is what I use,

我认为 JRE 中没有。您可以在 Apache HttpClient 等其他包中找到类似的功能。如果您不使用任何其他包,则只需编写自己的包。这并不难。这是我使用的,

public class QueryString {

 private Map<String, List<String>> parameters;

 public QueryString(String qs) {
  parameters = new TreeMap<String, List<String>>();

  // Parse query string
     String pairs[] = qs.split("&");
     for (String pair : pairs) {
            String name;
            String value;
            int pos = pair.indexOf('=');
            // for "n=", the value is "", for "n", the value is null
         if (pos == -1) {
          name = pair;
          value = null;
         } else {
       try {
        name = URLDecoder.decode(pair.substring(0, pos), "UTF-8");
              value = URLDecoder.decode(pair.substring(pos+1, pair.length()), "UTF-8");            
       } catch (UnsupportedEncodingException e) {
        // Not really possible, throw unchecked
           throw new IllegalStateException("No UTF-8");
       }
         }
         List<String> list = parameters.get(name);
         if (list == null) {
          list = new ArrayList<String>();
          parameters.put(name, list);
         }
         list.add(value);
     }
 }

 public String getParameter(String name) {        
  List<String> values = parameters.get(name);
  if (values == null)
   return null;

  if (values.size() == 0)
   return "";

  return values.get(0);
 }

 public String[] getParameterValues(String name) {        
  List<String> values = parameters.get(name);
  if (values == null)
   return null;

  return (String[])values.toArray(new String[values.size()]);
 }

 public Enumeration<String> getParameterNames() {  
  return Collections.enumeration(parameters.keySet()); 
 }

 public Map<String, String[]> getParameterMap() {
  Map<String, String[]> map = new TreeMap<String, String[]>();
  for (Map.Entry<String, List<String>> entry : parameters.entrySet()) {
   List<String> list = entry.getValue();
   String[] values;
   if (list == null)
    values = null;
   else
    values = (String[]) list.toArray(new String[list.size()]);
   map.put(entry.getKey(), values);
  }
  return map;
 } 
}

回答by Andreas

Based on the answer from BalusC, i wrote some example-Java-Code:

根据 BalusC 的回答,我写了一些示例 Java 代码:

    if (queryString != null)
    {
        final String[] arrParameters = queryString.split("&");
        for (final String tempParameterString : arrParameters)
        {
            final String[] arrTempParameter = tempParameterString.split("=");
            if (arrTempParameter.length >= 2)
            {
                final String parameterKey = arrTempParameter[0];
                final String parameterValue = arrTempParameter[1];
                //do something with the parameters
            }
        }
    }

回答by Patrick O'Leary

On Android, you can use the Uri.parse static method of the android.net.Uriclass to do the heavy lifting. If you're doing anything with URIs and Intents you'll want to use it anyways.

在 Android 上,您可以使用android.net.Uri类的 Uri.parse 静态方法来完成繁重的工作。如果您正在对 URI 和 Intent 做任何事情,您无论如何都会想要使用它。

回答by dfrankow

Here is BalusC's answer, but it compiles and returns results:

这是BalusC 的答案,但它编译并返回结果:

public static Map<String, List<String>> getUrlParameters(String url)
        throws UnsupportedEncodingException {
    Map<String, List<String>> params = new HashMap<String, List<String>>();
    String[] urlParts = url.split("\?");
    if (urlParts.length > 1) {
        String query = urlParts[1];
        for (String param : query.split("&")) {
            String pair[] = param.split("=");
            String key = URLDecoder.decode(pair[0], "UTF-8");
            String value = "";
            if (pair.length > 1) {
                value = URLDecoder.decode(pair[1], "UTF-8");
            }
            List<String> values = params.get(key);
            if (values == null) {
                values = new ArrayList<String>();
                params.put(key, values);
            }
            values.add(value);
        }
    }
    return params;
}

回答by diyism

On Android:

在安卓上:

import android.net.Uri;

[...]

Uri uri=Uri.parse(url_string);
uri.getQueryParameter("para1");

回答by wafna

public static Map <String, String> parseQueryString (final URL url)
        throws UnsupportedEncodingException
{
    final Map <String, String> qps = new TreeMap <String, String> ();
    final StringTokenizer pairs = new StringTokenizer (url.getQuery (), "&");
    while (pairs.hasMoreTokens ())
    {
        final String pair = pairs.nextToken ();
        final StringTokenizer parts = new StringTokenizer (pair, "=");
        final String name = URLDecoder.decode (parts.nextToken (), "ISO-8859-1");
        final String value = URLDecoder.decode (parts.nextToken (), "ISO-8859-1");
        qps.put (name, value);
    }
    return qps;
}