แยกสตริงการสืบค้นบน Android


271

Java EE มีServletRequest.getParameterValues ​​()()

บนแพลตฟอร์มที่ไม่ใช่ EE, URL.getQuery ()จะส่งคืนสตริง

เป็นวิธีปกติในการแยกวิเคราะห์สตริงแบบสอบถามใน URL อย่างถูกต้องเมื่อไม่ได้อยู่ใน Java EE อะไร


< คุยโว >

เป็นที่นิยมในคำตอบให้ลองทำ parser ของคุณเอง นี่เป็นโครงการไมโครโค้ดที่น่าสนใจและน่าตื่นเต้น แต่ฉันไม่สามารถพูดได้ว่ามันเป็นความคิดที่ดี :(

ตัวอย่างโค้ดด้านล่างนี้มีข้อบกพร่องหรือเสียโดยทั่วไป btw ทำลายพวกเขาคือการออกกำลังกายที่น่าสนใจสำหรับผู้อ่าน และเพื่อแฮกเกอร์โจมตีเว็บไซต์ที่ใช้งานและให้แฮกเกอร์โจมตีเว็บไซต์ที่ใช้พวกเขา

การแยกสตริงข้อความค้นหาเป็นปัญหาที่กำหนดไว้อย่างดี แต่การอ่านข้อมูลจำเพาะและทำความเข้าใจกับความแตกต่างนั้นไม่ใช่เรื่องเล็กน้อย มันดีกว่าที่จะปล่อยให้ coder ไลบรารีแพลตฟอร์มทำงานหนักและทำการแก้ไขสำหรับคุณ!

< / คุยโว >


คุณสามารถโพสต์ URL ตัวอย่างสิ่งที่คุณได้รับgetQuery()และสิ่งที่คุณต้องการรับเป็นผลลัพธ์ได้หรือไม่
Thomas Owens

1
คุณต้องการทำสิ่งนี้จากเซิร์ฟเล็ตหรือเพจ JSP หรือไม่? ฉันต้องการคำชี้แจงบางอย่างก่อนที่จะตอบ
ChadNC

1
คุณต้องการแยกพารามิเตอร์ POST หรือไม่
Thilo

2
แม้ว่าคุณจะอยู่ใน J2EE (หรือทางทิศตะวันออกกับแพ็คเกจ EE บางตัวที่ถูกเพิ่มผ่าน OSGi เช่นเดียวกับฉัน) คำถามนี้ก็สมเหตุสมผลแล้ว ในกรณีของฉันแบบสอบถามสตริง / url เข้ารหัส POST ServletRequestร่างกายจะดำเนินการโดยส่วนหนึ่งของระบบที่จงใจไม่เชื่อเรื่องพระเจ้าสิ่งที่เหมือน
Hanno Fietz

61
อัปเกรดแล้วสำหรับ <rant />!
Nowaker

คำตอบ:


65

ตั้งแต่สิ่งที่ Android M มีความซับซ้อนมากขึ้น คำตอบของandroid.net.URI .getQueryParameter () มีข้อผิดพลาดซึ่งแบ่งช่องว่างก่อน JellyBean Apache URLEncodedUtils.parse () ใช้งานได้ แต่เลิกใช้ใน Lและลบออกใน Mลบออกในเอ็ม

ดังนั้นคำตอบที่ดีที่สุดในตอนนี้คือUrlQuerySanitizer UrlQuerySanitizerสิ่งนี้มีอยู่ตั้งแต่ API ระดับ 1 และยังคงมีอยู่ นอกจากนี้ยังทำให้คุณคิดถึงปัญหาที่ยุ่งยากเช่นคุณจัดการกับอักขระพิเศษหรือค่าซ้ำ ๆ

รหัสที่ง่ายที่สุดคือ

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

หากคุณมีความสุขกับพฤติกรรมการแยกวิเคราะห์เริ่มต้นคุณสามารถทำได้:

new UrlQuerySanitizer(url).getValue("paramName")

แต่คุณควรตรวจสอบให้แน่ใจว่าคุณเข้าใจว่าพฤติกรรมการแยกวิเคราะห์เริ่มต้นคืออะไรเพราะอาจไม่ใช่สิ่งที่คุณต้องการ


4
URLQuerySanitizer.getAllButNullLegal () ส่งคืน UrlQuerySanitizer.ValueSanitizer ไม่ใช่ UrlQuerySanitizer
Peter Zhao

31
ด้วยเหตุผลบางอย่างข้างต้นไม่ได้สำหรับฉันฉันต้องแก้ไขมันเพียงเล็กน้อย - ซึ่งทำให้ง่ายยิ่งขึ้น:UrlQuerySanitizer sanitizer = new UrlQuerySanitizer(YourStringURL); String value = sanitizer.getValue("parameter");
SeBsZ

3
ไม่ทำงาน. UrlQuerySanitizer ใน sdk-23 มีเพียงวิธีเดียวเท่านั้นsanitize()
Ninja

_นี้จะถอดรหัสตัวอักษรพิเศษและอีโมจิ ฉันต้องไปกับstackoverflow.com/a/35638979/1155282
Irshu

มีไลบรารีของเฟรมเวิร์กที่เทียบเท่ากับสปริงนี้หรือไม่?
iamjoshua

202

บน Android:

import android.net.Uri;

[...]

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

20
โปรดทราบว่าสิ่งนี้ใช้คลาส Uri ไม่ใช่คลาส URI (Uri เป็นส่วนหนึ่งของ android.net ในขณะที่ URI เป็นส่วนหนึ่งของ java.net)
Marius

5
นอกจากนี้โปรดทราบว่าก่อนหน้านี้กับ Ice Cream Sandwich สิ่งนี้จะล้มเหลวในการแยก + อักขระในค่าของอักขระเว้นวรรค
rpetrich

@rpetrich เอกสารจริงบอกว่ามีข้อผิดพลาดก่อน Jelly Bean รวมถึง Ice Cream Sandwich ref
Big McLargeHuge

64

9
สิ่งนี้มีอยู่ใน apache http client library ไม่ใช่เฉพาะใน Android Btw ลิงก์ไปยัง apache เปลี่ยนไป ล่าสุดคือ: hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/…
Cristian Vrabie

9
URLEncodedUtils.parse()ผลตอบแทนที่น่ารำคาญListที่คุณจะต้องผ่านการวนลูปเพื่อหาค่าสำหรับคีย์เฉพาะ มันจะดีกว่านี้ถ้ามันตอบกลับMapในคำตอบของ BalusC
Asaph

1
@Hanno Fietz คุณหมายถึงคุณไว้วางใจทางเลือกเหล่านี้หรือไม่? ฉันรู้ว่าพวกเขาเป็นรถ ฉันรู้ว่าการชี้ให้เห็นข้อบกพร่องที่ฉันเห็นจะกระตุ้นให้ผู้คนนำเวอร์ชันที่ "คงที่" ไปใช้เท่านั้นแทนที่จะมองหาข้อบกพร่องที่ฉันมองข้าม
จะ

1
@ Will - ดีฉันไม่เคยจะเชื่อถือตัวอย่างข้อมูลคัดลอกและวางที่ฉันได้รับจากเว็บไซต์ใด ๆ และไม่มีใครควรทำ แต่ที่นี่ตัวอย่างเหล่านี้ค่อนข้างได้รับการตรวจสอบและแสดงความคิดเห็นเป็นอย่างดีและมีareประโยชน์จริง ๆ เพียงแค่เห็นคำแนะนำบางอย่างเกี่ยวกับสิ่งที่อาจผิดกับรหัสนี้เป็นวิธีที่ดีในการคิดด้วยตนเอง และใจคุณฉันไม่ได้ตั้งใจจะพูดว่า "ม้วนตัวคุณเองดีกว่า" แต่มันก็ดีที่มีเนื้อหาที่ดีสำหรับการตัดสินใจอย่างชาญฉลาดในรหัสของฉันเอง
Hanno Fietz

8
ฉันคิดว่าการแยกวิเคราะห์ส่งคืนรายการเพื่อให้มันรักษาตำแหน่งการสั่งซื้อและอนุญาตรายการที่ซ้ำกันได้ง่ายขึ้น
dhaag23

26

นี่คือคำตอบของ 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;
}

1
JVM หมายเหตุ: ฉันใช้งานสิ่งนี้ใน Scala โดยใช้ Java Collections; นี่คือส่วนสำคัญ github: gist.github.com/3504765
Jay Taylor

2
ผมขอแนะนำให้เปลี่ยนString pair[] = param.split("=");เข้าสู่String pair[] = param.split("=", 2);การแยกคีย์ = ค่าคู่เฉพาะในเกิดขึ้นครั้งแรก ฉันเชื่อว่ามันได้รับอนุญาตให้มีเครื่องหมายเท่ากับค่าที่ไม่ได้เข้ารหัส
Dennie

22

หากคุณมี libty (เซิร์ฟเวอร์หรือไคลเอนต์) libs บน classpath ของคุณคุณสามารถใช้คลาส jetty util (ดูjavadoc ) เช่น:

import org.eclipse.jetty.util.*;
URL url = new URL("www.example.com/index.php?foo=bar&bla=blub");
MultiMap<String> params = new MultiMap<String>();
UrlEncoded.decodeTo(url.getQuery(), params, "UTF-8");

assert params.getString("foo").equals("bar");
assert params.getString("bla").equals("blub");

13

หากคุณกำลังใช้ Spring 3.1 หรือสูงกว่า (หวังว่าการสนับสนุนนั้นจะกลับมาอีก) คุณสามารถใช้UriComponentsและUriComponentsBuilder:

UriComponents components = UriComponentsBuilder.fromUri(uri).build();
List<String> myParam = components.getQueryParams().get("myParam");

components.getQueryParams() ส่งคืน MultiValueMap<String, String>

นี่คือบางส่วนเอกสารอื่น


นี่คือสิ่งที่ฉันกำลังมองหา คำถามของฉันคือฉันจะได้รับ uri ได้อย่างไร ฉันติดอยู่กับการบำรุงรักษารหัสที่ฉันไม่สามารถเปลี่ยนแปลงได้มากและเราไม่ได้ใช้ HttpServlet แทนที่จะใช้คำอธิบายประกอบและ Spring (@Get, @Produces (mediaType) และ @Path ("/ dataAsJSON / datafield / {datafield})) เพียงแค่ต้องการทราบวิธีรับสตริงแบบสอบถามเพื่อให้ฉันสามารถแยกวิเคราะห์ตามที่แสดงใน ตัวอย่างนี้
Nelda.techspiress

5

สำหรับเซิร์ฟเล็ตหรือเพจ JSP คุณสามารถรับคู่คีย์ / ค่าการสืบค้นโดยใช้ request.getParameter ("paramname")

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

มีวิธีอื่นในการทำ แต่นั่นคือวิธีที่ฉันทำในหน้า servlets และ jsp ทั้งหมดที่ฉันสร้าง


3
HttpServletRequest เป็นส่วนหนึ่งของ J2EE ที่เขาไม่มี การใช้ getParamter () ก็ไม่ใช่การแยกวิเคราะห์จริงๆ
Mr. Shiny และ New 安宇

3
โปรดสละเวลาอ่านความคิดเห็นที่ฉันขอให้ชี้แจงคำถามของเขา คำตอบนี้เป็นการตอบสนองต่อความคิดเห็นของเขาซึ่งเขากล่าวว่า "ฉันกำลังพยายามทำสิ่งนี้บน Android แต่คำตอบทั้งหมดบนแพลตฟอร์มทั้งหมดจะเป็นคำตอบที่มีประโยชน์ที่อาจให้คำแนะนำ (เช่นกับคนอื่น ๆ คำถาม) ดังนั้นอย่าระงับ! " ฉันตอบคำถามของเขาตามความคิดเห็นนั้น หากคุณไม่มีสิ่งใดที่มีประโยชน์ในการเพิ่มอย่าเพิ่มสิ่งใดเลย
ChadNC

1
อย่าอารมณ์เสียเกินไป "สิ่งนี้ไม่ตอบคำถาม" มีประโยชน์ในการเพิ่ม IMO
นายเงางามและใหม่安宇

1
มันไม่สำคัญสำหรับ Android หรือไม่คำถามก็คือวิธีการแยกสตริงที่มี URL และรับพารามิเตอร์ URL จากมัน สิ่งที่คุณกำลังย้ายที่นี่เป็นส่วนหนึ่งของ Servlet API โดยที่ Servlet container แยกวิเคราะห์พารามิเตอร์ขาเข้าจากคำขอ HTTP สำหรับคุณ มันไม่เกี่ยวข้องเนื่องจากคำถามเกี่ยวกับการแยกสตริงที่มี URL ไม่ใช่คำขอ HTTP และไม่อยู่ในคอนเทนเนอร์ Servlet
mvmn

5

บน Android ฉันลองใช้ @diyism คำตอบ แต่ฉันพบปัญหาช่องว่างที่ยกโดย @rpetrich ตัวอย่างเช่น: ฉันกรอกแบบฟอร์มที่username = "us+us"และpassword = "pw pw"ทำให้สตริง URL ดูเหมือน:

http://somewhere?username=us%2Bus&password=pw+pw

อย่างไรก็ตามรหัส @diyism ส่งคืน"us+us"และ"pw+pw"นั่นคือไม่พบอักขระเว้นวรรค หาก URL ถูกเขียนใหม่ด้วย%20อักขระช่องว่างจะได้รับการระบุ:

http://somewhere?username=us%2Bus&password=pw%20pw

สิ่งนี้นำไปสู่การแก้ไขต่อไปนี้:

Uri uri = Uri.parse(url_string.replace("+", "%20"));
uri.getQueryParameter("para1");

replace(" ", "%20")สิ่งนี้รู้สึกผิด แต่เคล็ดลับสำหรับฉัน: D
Mārtiņš Briedis

ไวยากรณ์ที่ถูกต้องควรเป็น "สตริงบางส่วน" .replaceAll ("[+]", "% 20");
RRTW

4

การแยกสตริงข้อความค้นหานั้นซับซ้อนกว่าที่คิดเล็กน้อยขึ้นอยู่กับว่าคุณต้องการให้อภัย

ก่อนอื่นสตริงการสืบค้นคือ ASCII ไบต์ คุณอ่านทีละไบต์และแปลงเป็นอักขระ ถ้าตัวละครเป็น? หรือ & จากนั้นมันจะส่งสัญญาณการเริ่มต้นของชื่อพารามิเตอร์ ถ้าตัวละครเป็น = ก็จะส่งสัญญาณการเริ่มต้นของค่าพารามิเตอร์ ถ้าตัวละครเป็น% ก็จะส่งสัญญาณเริ่มต้นของการเข้ารหัสไบต์ นี่คือที่ที่มันยาก

เมื่อคุณอ่านด้วยอักขระ% char คุณต้องอ่านสองไบต์ถัดไปและตีความเป็นตัวเลขฐานสิบหก นั่นหมายความว่าสองไบต์ถัดไปจะเป็น 0-9, af หรือ AF กาวเลขฐานสองหกเหล่านี้เข้าด้วยกันเพื่อรับค่าไบต์ของคุณ แต่จำไว้ไบต์ไม่ได้ตัวละคร คุณต้องรู้ว่าการเข้ารหัสใดที่ใช้ในการเข้ารหัสอักขระ อักขระéไม่ได้เข้ารหัสเหมือนกันใน UTF-8 เช่นเดียวกับใน ISO-8859-1 โดยทั่วไปแล้วเป็นไปไม่ได้ที่จะรู้ว่าการเข้ารหัสใดที่ใช้สำหรับชุดอักขระที่กำหนด ฉันมักจะใช้ UTF-8 เสมอเพราะเว็บไซต์ของฉันได้รับการกำหนดค่าเพื่อให้บริการทุกอย่างโดยใช้ UTF-8 แต่ในทางปฏิบัติคุณไม่แน่ใจ ตัวแทนผู้ใช้บางรายจะบอกการเข้ารหัสอักขระในคำขอ คุณสามารถลองอ่านได้ว่าหากคุณมีคำขอ HTTP แบบเต็ม หากคุณเพิ่งมี URL แยกกันขอให้โชคดี

อย่างไรก็ตามสมมติว่าคุณกำลังใช้ UTF-8 หรือการเข้ารหัสอักขระแบบหลายไบต์อื่น ๆ ตอนนี้คุณได้ถอดรหัสหนึ่งไบต์ที่เข้ารหัสแล้วคุณต้องตั้งค่าไว้จนกว่าคุณจะจับไบต์ต่อไป คุณต้องการไบต์ที่เข้ารหัสทั้งหมดที่อยู่ด้วยกันเพราะคุณไม่สามารถถอดรหัส url ได้อย่างถูกต้องทีละหนึ่งไบต์ จัดสรรไบต์ทั้งหมดที่อยู่ด้วยกันแล้วถอดรหัสพวกมันทั้งหมดในครั้งเดียวเพื่อสร้างตัวละครของคุณขึ้นมาใหม่

นอกจากนี้ยังได้รับความสนุกสนานมากขึ้นหากคุณต้องการผ่อนปรนและบัญชีตัวแทนผู้ใช้ที่ยุ่งเหยิง URL ตัวอย่างเช่นบางเว็บเมลไคลเอ็นต์มีการเข้ารหัสสองสิ่ง หรือสองขึ้นและตัวอักษร =? (ตัวอย่างเช่น: http://yoursite.com/blah??p1==v1&&p2==v2) หากคุณต้องการพยายามจัดการกับสิ่งนี้อย่างสง่างามคุณจะต้องเพิ่มตรรกะเพิ่มเติมให้กับ parser ของคุณ


ที่ไม่ได้อธิบายวิธีการแยกหรือดึงค่าพารามิเตอร์การสืบค้น
ChadNC

ถูกต้อง แต่ค่อนข้างยุ่งยาก เพื่อที่เรามี URLDecoder
BalusC

2
@ChadNC: ประโยคที่สามบอกวิธีการแยกวิเคราะห์: อ่านทีละหนึ่งไบต์และแปลงเป็นตัวอักษร ประโยคที่สี่เตือนคุณถึงตัวอักษรพิเศษ เป็นต้นคุณอาจไม่ได้อ่านคำตอบ?
นายเงางามและใหม่安宇

@BalusC: URLDecoder ทำงานได้ แต่มีโหมดความล้มเหลวบางอย่างหากคุณพยายามผ่อนปรนใน URL ที่คุณยอมรับ
นายเงางามและใหม่安宇

1
เห็นด้วยกับ @ Mr.ShinyAndNew การแยกวิเคราะห์แบบสอบถามไม่ใช่เรื่องง่าย ฉันสนับสนุน FIQL และนี่กลายเป็นความเจ็บปวดที่แท้จริงในตูด ตัวอย่างเช่น: yoursite.com/blah??p1==v1&&p2==v2,p2==v3;p2==v4
rafa.ferreira

4

บน Android มันง่ายเหมือนรหัสด้านล่าง:

UrlQuerySanitizer sanitzer = new UrlQuerySanitizer(url);
String value = sanitzer.getValue("your_get_parameter");

นอกจากนี้หากคุณไม่ต้องการลงทะเบียนการใช้คีย์คิวรีแต่ละรายการ:

sanitzer.setAllowUnregisteredParamaters(true)

ก่อนโทร:

sanitzer.parseUrl(yourUrl)

4

ฉันมีวิธีการเพื่อให้บรรลุนี้:

1) :

public static String getQueryString(String url, String tag) {
    String[] params = url.split("&");
    Map<String, String> map = new HashMap<String, String>();
    for (String param : params) {
        String name = param.split("=")[0];
        String value = param.split("=")[1];
        map.put(name, value);
    }

    Set<String> keys = map.keySet();
    for (String key : keys) {
        if(key.equals(tag)){
         return map.get(key);
        }
        System.out.println("Name=" + key);
        System.out.println("Value=" + map.get(key));
    }
    return "";
}

2) และวิธีที่ง่ายที่สุดในการทำสิ่งนี้โดยใช้คลาสUri :

public static String getQueryString(String url, String tag) {
    try {
        Uri uri=Uri.parse(url);
        return uri.getQueryParameter(tag);
    }catch(Exception e){
        Log.e(TAG,"getQueryString() " + e.getMessage());
    }
    return "";
}

และนี่คือตัวอย่างของวิธีใช้หนึ่งในสองวิธี:

String url = "http://www.jorgesys.com/advertisements/publicidadmobile.htm?position=x46&site=reform&awidth=800&aheight=120";      
String tagValue = getQueryString(url,"awidth");

ค่าของ tagValue คือ 800


3

บน Android คุณสามารถใช้วิธีคงที่ Uri.parse ของคลาสandroid.net.Uriเพื่อทำการยกของหนัก หากคุณทำอะไรกับยูริสและเจตจำนงคุณจะต้องใช้มันต่อไป


3

สำหรับการอ้างอิงนี่คือสิ่งที่ฉันได้รับ (อ้างอิงจาก URLEncodedUtils และส่งคืนแผนที่)

คุณสมบัติ:

  • มันยอมรับส่วนสตริงแบบสอบถามของ URL (คุณสามารถใช้request.getQueryString())
  • สตริงแบบสอบถามที่ว่างเปล่าจะผลิตที่ว่างเปล่า Map
  • พารามิเตอร์ที่ไม่มีค่า (? ทดสอบ) จะถูกแมปกับค่าว่าง List<String>

รหัส:

public static Map<String, List<String>> getParameterMapOfLists(String queryString) {
    Map<String, List<String>> mapOfLists = new HashMap<String, List<String>>();
    if (queryString == null || queryString.length() == 0) {
        return mapOfLists;
    }
    List<NameValuePair> list = URLEncodedUtils.parse(URI.create("http://localhost/?" + queryString), "UTF-8");
    for (NameValuePair pair : list) {
        List<String> values = mapOfLists.get(pair.getName());
        if (values == null) {
            values = new ArrayList<String>();
            mapOfLists.put(pair.getName(), values);
        }
        if (pair.getValue() != null) {
            values.add(pair.getValue());
        }
    }

    return mapOfLists;
}

ผู้ช่วยที่เข้ากันได้ (ค่าจะถูกเก็บไว้ในอาร์เรย์สตริงเช่นเดียวกับในServletRequest.getParameterMap () ):

public static Map<String, String[]> getParameterMap(String queryString) {
    Map<String, List<String>> mapOfLists = getParameterMapOfLists(queryString);

    Map<String, String[]> mapOfArrays = new HashMap<String, String[]>();
    for (String key : mapOfLists.keySet()) {
        mapOfArrays.put(key, mapOfLists.get(key).toArray(new String[] {}));
    }

    return mapOfArrays;
}

3

มันใช้งานได้สำหรับฉัน .. ฉันไม่แน่ใจว่าทำไมทุกคนอยู่หลังแผนที่รายชื่อ> สิ่งที่ฉันต้องการคือแผนที่ค่าชื่อธรรมดา

เพื่อให้ง่ายขึ้นฉันใช้ build ใน URI.getQuery ();

public static Map<String, String> getUrlParameters(URI uri)
    throws UnsupportedEncodingException {
    Map<String, String> params = new HashMap<String, String>();
    for (String param : uri.getQuery().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");
        }
        params.put(new String(key), new String(value));
    }
    return params;
}

1
วิธีการเกี่ยวกับรูปแบบที่มีหลายตัวเลือก? เป็นเรื่องปกติอย่างสมบูรณ์ที่จะมีคีย์ซ้ำในสตริงการสืบค้นที่ถูกต้อง (และเนื้อหาของฟอร์ม POST) มีข้อบกพร่องอื่น ๆ และกรณีมุมไม่ครอบคลุม; หลายคนถูกกล่าวถึงในความเห็นเกี่ยวกับวิธีการอื่น ๆ ฉันจะละเว้นรูปแบบชี้ให้พวกเขาออกในความหวาดกลัวที่คุณแก้ไขมันแทนการใช้ห้องสมุดที่มีคุณภาพตามฉันพูดจาโผงผางในคำถาม;)
Will

2

Multimap ของ Guava เหมาะสมกว่าสำหรับสิ่งนี้ นี่เป็นเวอร์ชั่นย่อสั้น ๆ :

Multimap<String, String> getUrlParameters(String url) {
        try {
            Multimap<String, String> ret = ArrayListMultimap.create();
            for (NameValuePair param : URLEncodedUtils.parse(new URI(url), "UTF-8")) {
                ret.put(param.getName(), param.getValue());
            }
            return ret;
        } catch (URISyntaxException e) {
            throw new RuntimeException(e);
        }
    }

1

Apache AXIS2 มีการติดตั้ง QueryStringParser.java หากคุณไม่ได้ใช้ Axis2 เพียงดาวน์โหลดซอร์สโค้ดและเคสจากที่นี่ -

http://svn.apache.org/repos/asf/axis/axis2/java/core/trunk/modules/kernel/src/org/apache/axis2/transport/http/util/QueryStringParser.java

http://svn.apache.org/repos/asf/axis/axis2/java/core/trunk/modules/kernel/test/org/apache/axis2/transport/http/util/QueryStringParserTest.java


1

Origanally ตอบที่นี่

บน Android มีระดับ Uri ในแพคเกจandroid.net โปรดทราบว่า Uri เป็นส่วนหนึ่งของ android.net ในขณะที่ URI เป็นส่วนหนึ่งของ java.net

คลาส Uri มีฟังก์ชันมากมายในการแยกคู่คีย์ - ค่าคิวรี ป้อนคำอธิบายรูปภาพที่นี่

ฟังก์ชั่นดังต่อไปนี้จะส่งกลับคู่คีย์ - ค่าในรูปแบบของ HashMap

ใน Java:

Map<String, String> getQueryKeyValueMap(Uri uri){
    HashMap<String, String> keyValueMap = new HashMap();
    String key;
    String value;

    Set<String> keyNamesList = uri.getQueryParameterNames();
    Iterator iterator = keyNamesList.iterator();

    while (iterator.hasNext()){
        key = (String) iterator.next();
        value = uri.getQueryParameter(key);
        keyValueMap.put(key, value);
    }
    return keyValueMap;
}

ใน Kotlin:

fun getQueryKeyValueMap(uri: Uri): HashMap<String, String> {
        val keyValueMap = HashMap<String, String>()
        var key: String
        var value: String

        val keyNamesList = uri.queryParameterNames
        val iterator = keyNamesList.iterator()

        while (iterator.hasNext()) {
            key = iterator.next() as String
            value = uri.getQueryParameter(key) as String
            keyValueMap.put(key, value)
        }
        return keyValueMap
    }

0

ฉันไม่คิดว่าจะมีหนึ่งใน 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;
 } 
}

มีวิธีอะไรกับคลาสอาปาเช่?
จะ

1
คุณสามารถใช้การแยกวิเคราะห์ () วิธีการ: hc.apache.org/httpcomponents-client/httpclient/apidocs/org/…
ZZ Coder

3
กรุณาใส่ลิงค์ apache คอมมอนส์ในคำตอบของตัวเองเพื่อให้ฉันสามารถลงคะแนนได้
itsadok

0

จากคำตอบของ 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
            }
        }
    }

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


0

ใช้ฝรั่ง:

Multimap<String,String> parseQueryString(String queryString, String encoding) {
    LinkedListMultimap<String, String> result = LinkedListMultimap.create();

    for(String entry : Splitter.on("&").omitEmptyStrings().split(queryString)) {
        String pair [] = entry.split("=", 2);
        try {
            result.put(URLDecoder.decode(pair[0], encoding), pair.length == 2 ? URLDecoder.decode(pair[1], encoding) : null);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    return result;
}

0

ตอบที่นี่เพราะนี่เป็นกระทู้ยอดนิยม นี่เป็นโซลูชันที่สะอาดใน Kotlin ที่ใช้UrlQuerySanitizerAPI ที่แนะนำ ดูเอกสารอย่างเป็นทางการ ฉันได้เพิ่มตัวสร้างสตริงเพื่อต่อเชื่อมและแสดงพารามิเตอร์

    var myURL: String? = null
    // if the url is sent from a different activity where you set it to a value
    if (intent.hasExtra("my_value")) {
        myURL = intent.extras.getString("my_value")
    } else {
        myURL = intent.dataString
    }

    val sanitizer = UrlQuerySanitizer(myURL)
    // We don't want to manually define every expected query *key*, so we set this to true
    sanitizer.allowUnregisteredParamaters = true
    val parameterNamesToValues: List<UrlQuerySanitizer.ParameterValuePair> = sanitizer.parameterList
    val parameterIterator: Iterator<UrlQuerySanitizer.ParameterValuePair> = parameterNamesToValues.iterator()

    // Helper simply so we can display all values on screen
    val stringBuilder = StringBuilder()

    while (parameterIterator.hasNext()) {
        val parameterValuePair: UrlQuerySanitizer.ParameterValuePair = parameterIterator.next()
        val parameterName: String = parameterValuePair.mParameter
        val parameterValue: String = parameterValuePair.mValue

        // Append string to display all key value pairs
        stringBuilder.append("Key: $parameterName\nValue: $parameterValue\n\n")
    }

    // Set a textView's text to display the string
    val paramListString = stringBuilder.toString()
    val textView: TextView = findViewById(R.id.activity_title) as TextView
    textView.text = "Paramlist is \n\n$paramListString"

    // to check if the url has specific keys
    if (sanitizer.hasParameter("type")) {
        val type = sanitizer.getValue("type")
        println("sanitizer has type param $type")
    }

-2

วิธีนี้ใช้ uri และส่งคืนแผนที่ของชื่อพาร์และมูลค่าที่ตราไว้

  public static Map<String, String> getQueryMap(String uri) {

    String queryParms[] = uri.split("\\?");

    Map<String, String> map = new HashMap<>();// 

    if (queryParms == null || queryParms.length == 0) return map;

    String[] params = queryParms[1].split("&");
    for (String param : params) {
        String name = param.split("=")[0];
        String value = param.split("=")[1];
        map.put(name, value);
    }
    return map;
}

1
ตามคำพูดของฉันข้างต้นนี้สามารถทำผิดพลาดเล็กน้อย อย่ากังวลกับการแก้ไขเพียงใช้ไลบรารียูทิลิตี้ระดับมืออาชีพแทน
จะ

-3

คุณพูดว่า "Java" แต่ "ไม่ใช่ Java EE" คุณหมายความว่าคุณกำลังใช้ JSP และ / หรือ servlets แต่ไม่ใช่ Java EE สแต็กเต็มหรือไม่ หากเป็นกรณีนี้คุณควรจะมี request.getParameter () ให้บริการ

หากคุณหมายถึงว่าคุณกำลังเขียน Java แต่คุณไม่ได้กำลังเขียน JSP หรือ servlets หรือว่าคุณเพิ่งใช้ 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

(ฉันสามารถเขียนโค้ด Java แต่นั่นจะไม่มีประโยชน์เพราะถ้าคุณมี Java ให้ใช้คุณสามารถใช้ request.getParameters)


ระวังการเข้ารหัสตัวอักษรเมื่อ url- ถอดรหัสเลขฐานสิบหก
นายเงางามและใหม่安宇

มันเป็น Android ดังนั้น Java แต่ไม่ใช่ J2EE
Andrzej Doyle

ฉันลืมที่จะพูดถึง: คุณต้องตรวจสอบ "+" ซึ่งควรแปลเป็นช่องว่าง การเว้นวรรคในตัวนั้นผิดกฎหมายในสตริงการสืบค้น
Jay
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.