Cắt xén truy vấn


19

Tôi biết bạn đã luôn nghĩ về những thử thách và khổ nạn khi trải nghiệm những niềm vui trong cuộc sống như một proxy web. Thành thật mà nói, ai không? Hôm nay bạn được giao nhiệm vụ hiện thực hóa mục tiêu này (ít nhất là một phần của nó). Trang web X nhận được rất nhiều lưu lượng truy cập hàng ngày và đang tìm kiếm PaaS (rõ ràng điều này đề cập đến Proxy là một Dịch vụ) vì số lượng lớn người dùng khăng khăng truyền thông tin nhạy cảm thông qua các tham số truy vấn (người dùng thật ngớ ngẩn). Nhiệm vụ của bạn là xóa bất kỳ và tất cả các tham số truy vấn nhạy cảm khỏi yêu cầu trước khi chuyển tiếp yêu cầu đến đích ban đầu.

Đầu vào

  • URL HTTP tuyệt đối được hình thành tốt tuân theo ngữ pháp URI trong RFC3986 Phần 3 .
    • Bạn có thể cho rằng không có mảnh vỡ
    • Ví dụ định dạng ngắn gọn trong đó mọi thứ trong ngoặc vuông biểu thị tùy chọn: http[s]://[user:pass@]host.name.com[:port]/[?param1=value1&param2=value2...]
  • Một danh sách các tham số truy vấn sẽ được loại bỏ.

Đầu ra

URL HTTP được sửa đổi mà không có các tham số được xác định trong danh sách đầu vào.

Ví dụ

http://example.com/ [foo]
> http://example.com/

http://example.com/?foo=bar []
> http://example.com/?foo=bar

http://example.com/ []
> http://example.com/

http://example.com/?foo=1&bar=2&baz=3 [foo,baz]
> http://example.com/?bar=2

http://example.com/?foo=1&bar=2&baz=3 [foo,bar,baz]
> http://example.com/

http://example.com/?foo&bar=2&baz= [foo,baz]
> http://example.com/?bar=2

http://example.com/?abc=1&def=2&baz=foo [foo,bar]
> http://example.com/?abc=1&def=2&baz=foo

http://example.com/?foobar=baz [foo]
> http://example.com/?foobar=baz

http://foo:foo@foo.com:8080/?foo=1&bar=foo [foo]
> http://foo:foo@foo.com:8080/?bar=foo

Chấm điểm

Đây là , vì vậy câu trả lời ngắn nhất (tính bằng byte) sẽ thắng.


1
Tôi có thể lấy URL và các tham số truy vấn từng dòng trên các dòng riêng biệt không?
seshoumara

1
Có thể &xuất hiện bất cứ nơi nào khác ngoài giữa các tham số?
Riley

cũng có thể ví dụ mật khẩu chứa a ?? Cũng nên giữ trật tự như vậy?
KarlKastor

@Riley Không. Nếu &là một phần của tham số truy vấn, nó phải được mã hóa chính xác như là%26
Chọc

1
Rõ ràng, http://foo:&foo=x@foo.com:8080/?foo=1&bar=foođược cho phép bởi RFC. Điều này sẽ phá vỡ một loạt các giải pháp hiện có. : D (Quy tắc là userinfo có thể được mở rộng dưới dạng không được giám sát hoặc thoát khỏi pct hoặc các lần xóa phụ, và các lần &=
xóa

Câu trả lời:


6

GNU sed 98 96 88 80 77 74 69 59 54 (48 + 1 cho -r) 49

:;s,(.+)(=[^&]*[& ]|&)(.*)\1,\3 ,
t;s,[?&]? .*,,

Danh sách các tham số cần loại bỏ được phân tách bằng dấu cách.

$ echo 'http://example.com/?foo=1&bar=2&baz=3 foo bar baz' | sed -rf sed.txt
http://example.com/

$ echo 'http://example.com/?foo&bar=2&baz= foo baz' | sed -rf sed.txt
http://example.com/?bar=2

$ echo 'http://example.com/' | sed -rf sed.txt
http://example.com/

Trong chỉnh sửa mã hiện tại của bạn, nhiều bài kiểm tra từ câu hỏi của OP đưa ra một dấu &hoặc ?ký tự trong URL kết quả.
seshoumara

@seshoumara Tôi không chắc là mình đã bỏ lỡ điều đó như thế nào ... May mắn thay, đó chỉ là chênh lệch 1 byte.
Riley

Các phiên bản mã 96, 77 và 59 byte không được tìm thấy trong lịch sử chỉnh sửa của bạn. Chỉnh sửa tiêu đề 7 cho thấy ít hơn 10 byte so với chỉnh sửa 6, nhưng mã đã không được thay đổi. Tôi là nitpicking mặc dù, chơi golf tuyệt vời!
seshoumara

1
@seshoumara Tôi nghĩ rằng nó đã kết hợp một số chỉnh sửa vì chúng là thứ yếu (chỉ xóa một vài ký tự).
Riley

@seshoumara Tôi đoán nó thực sự kết hợp chúng vì tôi đã thực hiện nhiều chỉnh sửa trong vòng 5 phút với nhau.
Riley

5

JavaScript (ES6), 62 60 byte

f=
(s,a,u=new URL(s))=>a.map(e=>u.searchParams.delete(e))&&''+u
;
s.value=document.URL;
<div oninput=o.textContent=f(s.value,a.value.split`\n`)><input id=s><br><textarea id=a></textarea><pre id=o>

Chỉnh sửa: Đã lưu 2 byte nhờ @Shaggy.


Bạn có thể lưu 5 byte bằng cách thả .hrefvào cuối.
Shaggy

@Shaggy Điều đó sẽ không trả về một chuỗi ... Tôi đã cho rằng điều đó không được phép.
Neil

Nó phụ thuộc vào cách bạn xuất nó. Ví dụ, nếu bạn alerthoặc sử dụng chèn nó vào một nút (văn bản), như bạn có, nó sẽ cung cấp cho bạn thuộc hreftính của đối tượng. Tuy nhiên, nếu bạn đăng nhập nó vào bàn điều khiển, nó sẽ cung cấp cho bạn toàn bộ đối tượng. Xem Fiddle này .
Shaggy

1
@Shaggy Ah, vì vậy tôi chắc chắn có thể lưu 2 byte bằng cách xâu chuỗi nó, cảm ơn.
Neil

3

PHP, 90 byte

<?=trim(preg_replace("#(?<=\?|&)(".join("|",$_GET[r]).")(=.*)?(&|$)#U","",$_GET[u]),"?&");

-11 byte nếu? hoặc & được cho phép ở cuối

Phiên bản trước 140 byte

<?=substr($u=$_GET[u],0,strpos($u,"?")+!!$j=join("&",preg_grep("#^(".join("|",$_GET[r]).")(=|$)#",explode("&",parse_url($u)[query]),1))).$j;

+2 byte: Các lựa chọn thay thế phải được ngoặc đơn, hoặc ^/ (.*|$)sẽ là một phần của thay thế đầu tiên / cuối cùng.
Tít

-2 byte: loại bỏ .*. hoặc thay thế (=.*|$)bằng \b(-5).
Tít

Regrec của bạn sẽ trông giống như #^foo|bar(=.*|$)#là giống hệt với #(^foo)|(bar=.*|bar$))#. Nhưng nó nên được #(foo|bar)(=.*|$)#.
Tít

@Titus Bạn đúng là lỗi của tôi
Jörg Hülsermann

tốt đẹp! Tôi đã không nghĩ đến những lời khẳng định; đó là lý do tại sao tôi quay trở lại array_map(và tôi đã ngạc nhiên khi nó có thể bật ra ngắn như thế nào).
Tít

2

PHP, 120 110 byte

với các hàm preg numplace và mảng: (lấy cảm hứng từ Jörg )

<?=preg_replace(array_map(function($s){return"#(\\?|&)$s(=.*)?(&|$)#U";},array_slice($argv,2)),"\1",$argv[1]);

lưu vào tập tin, gọi với php <scriptname> <uri> <parametername> <parametername> ...

với parse_str và http_build_query (120 byte):

parse_str(end($u=explode('?',$argv[1])),$a);for($i=$argc;$i-->1;)unset($a[$argv[$i]]);echo"$u[0]?".http_build_query($a);

chạy với php -r <code> <uri> <parametername> <parametername> ...


parse_str? http_build_query? Tôi rất vui khi thấy ai đó làm việc bằng cách sử dụng các công cụ phù hợp cho công việc, ngay cả trong môn đánh gôn. Các lỗi phát sinh vì sử dụng URL / truy vấn SQL / regrec / HTML là "chỉ chuỗi" có số lượng nhiều như chúng có thể dễ dàng ngăn chặn.
Daerdemandt

Có lẽ để có thêm cảm hứng. Tôi hiểu bạn
Jörg Hülsermann

@Lynn Don Cheet bạn có việc gì làm tốt hơn là rình rập tôi không?
Tít

2

Java 7, 127 byte

String a(String a,String[]b){for(String c:b)a=a.replaceAll("(?<=[?&])"+c+"(=[^&]*)?(&|$)","");return a.replaceAll("[?&]$","");}

Giải trình

String sanitize(String url, String[] params) {
    for (String param : params) {
        // please don't modify function parameters in real code
        url=url.replaceAll("(?<=[?&])" // Look for a leading ? or & but don't consume it
            + param                    // Consume the key of the query param (assuming key=value syntax)
            + "(=[^&]*)?"              // Consume the value of the query param if it exists
            + "(&|$)","");             // Consume the trailing & unless we're at the end of the url and replace with nothing
    }
    url = url.replaceAll("[?&]$",""); // If we remove all of the params then we'll have a trailing ? which needs to be removed
                                      // If we remove the last param only then we could have a trailing & which also needs to be removed
                                      // We will only run into one of these scenarios
    return url;
}

Ý tưởng


Điều này không thành công đối với tôi khi sử dụng các ví dụ thứ 4, 5, 6 và 9 của bạn oO Tôi đang sử dụng Java 8, vì vậy đó có thể là nó. Mặc dù đã thử tương đương C # và nó đã thất bại trong các trường hợp tương tự, vì vậy idunno.
Yodle

1
Nevermind, làm rối tung cách tôi đang thử nghiệm nó.
Yodle

2

C #, 377 336 330 328 byte (173 alt)

string n(string u,string[]r){var s=u.Split('?');if(s.Length<2)return u;var a=s[1].Contains("&")?s[1].Split('&'):new string[]{s[1]};int B=a.Length,i=0,C=i,c=B;for(;i<B;i++)foreach(var R in r)if(R==a[i].Split('=')[0]){a[i]="";c--;}var t=s[0];t+=c>0?"?":"";for(i=0;i<a.Length;i++)if(a[i]!=""){t+=a[i];C++;if(C!=c)t+="&";}return t;}

Chương trình đầy đủ:

using System;
class a
{
    static void Main()
    {
        string input = Console.ReadLine();
        string url = input.Split(' ')[0];
        string r = input.Split(' ')[1];
        r = r.Replace("[", "").Replace("]","");
        string[] remove = r.Split(',');
        a b = new a();
        Console.WriteLine(b.n(url, remove));
    }
    string n(string u,string[]r)
    {
        var s=u.Split('?');
        if(s.Length<2)return u;
        var a=s[1].Contains("&")?s[1].Split('&'):new string[]{s[1]};
        int B=a.Length,i=0,C=i,c=B;
        for(;i<B;i++)
            foreach(var R in r)
                if(R==a[i].Split('=')[0])
                {
                    a[i]="";
                    c--;
                }
        var t=s[0];
        t+=c>0?"?":"";
        for(i=0;i<a.Length;i++)
            if(a[i]!="")
            {
                t+=a[i];
                C++;
                if (C!=c)t+="&";
            }
        return t;
    }
}

Có lẽ không hiệu quả lắm, nhưng tôi nghĩ nó hoạt động.

Ngoài ra, có một giải pháp 173 byte sử dụng phương thức @ Poke của Java. Yêu cầu nhập vào Regex, vì vậy có lẽ không thể ngắn hơn.

using System.Text.RegularExpressions;string m(string a,string[]b){foreach(var c in b)a=Regex.Replace(a,$"(?<=[?&]){c}(=[^&]*)?(&|$)","");return Regex.Replace(a,"[?&]$","");}

2

Ruby, 146 140 127 119 116 113 byte

chỉnh sửa 2: lưu 6 byte bằng cách sử dụng $1, $2$*, và 7 bằng cách thay đổi x.split("=")[0]thành x[/\w+/]
chỉnh sửa 3: lưu 6 byte bằng cách sử dụng *thay vì .joinlưu 2 byte từ các khoảng trắng không cần thiết
chỉnh sửa 4: lưu 3 byte bằng cách định dạng lại nội tuyến (thay đổi regex thành tương đương $*[1][/([^?]*)\??(.*)/,1]và đặt như được gán cho a)
chỉnh sửa 5: lưu 3 byte bằng cách sử dụng ($*[2].scan(r=/\w+/)&[x[r]])[0]thay vì$*[2].scan(r=/\w+/).include?(x[r])

Giả sử đầu vào cho chương trình khi chạy nó:

a,b=$*[1][/([^?]*)\??(.*)/,1],$2.split("&").reject{|x|($*[2].scan(r=/\w+/)&[x[r]])[0]}*"&"
puts(b[0] ?a+"?"+b: a)

Giải trình

a,b=$*[1][/([^?]*)\??(.*)/,1],$2.split("&")

Điều này phân tích cú pháp URL được đưa ra trên dòng lệnh và lưu các kết quả khớp vào $1$2. $*[1][/([^?]*)\??(.*)/,1]cũng trả về trận đấu đầu tiên để lưu trữ bên trong a, trong khi trận đấu thứ hai được gọi là $2 cho điểm tới $ 1 và phân tích bthành một mảng các mảng ...

.reject { |x|

... từ chối tất cả ...

    ($*[2].scan(r=/\w+/)&[x[r]])[0]

... có một chuỗi trước '=' được bao gồm trong danh sách các tên được cung cấp bởi tham số thứ hai ... Điều này hoạt động vì chúng tôi quét các từ (để lấy danh sách) sau đó lấy từ trước =và xem từ đó có trong danh sách với &. Vì &trả về một mảng trống trên "không tìm thấy" (tập hợp null), chúng tôi sử dụng mẹo được giải thích bên dưới để lấy nilnếu không có phần tử nào trong mảng. mặt khác, chúng ta trả về một chuỗi, được tính là trung thực, từ chối chuỗi đó.

}*"&"

... và nối các chuỗi còn lại cùng với '&'

Tại thời điểm này, blà chuỗi truy vấn GET cho URL. Vì vậy, chúng ta chỉ cần in nó.

puts(b[0] ?a+"?"+b: a)

Điều này sử dụng một mẹo trong ruby. b[0]sẽ là nilnếu b là một mảng hoặc chuỗi rỗng. Vì vậy, nếu nó truthy , (không nilhay false), sau đó có ít nhất một phần tử trong mảng, vì vậy chúng ta cần phải puts a+"?"+bcho URL đúng. mặt khác, chúng tôi chỉ đặt a, bởi vì không có tham số nào để hiển thị

Lưu ý: câu trả lời này giả định rằng ? không thể xuất hiện ở bất cứ đâu ngoại trừ việc phân định URL khỏi truy vấn. (theo những gì tôi đọc được từ RFC được liên kết)

Ngoài ra, đây là câu trả lời golf đầu tiên của tôi: D


2
Chào mừng đến với PPCG!
acrolith

1

Pip , 46 byte

Lấy URL từ stdin và các tham số truy vấn để xóa khỏi đối số dòng lệnh.

YgqR`\?.+`{s:J_@`^[^=]+`NIyFI@>a^'&[s&'?sJ'&]}

Hãy thử trực tuyến!

Giải trình:

 g               Local variable containing list of cmdline args
Y                Yank into global variable y so it's available inside the function
  q              Grab a line of stdin
   R`\?.+`{...}  Do a regex replace of everything from ? on, using a callback function:

s:J_@`^[^=]+`NIyFI@>a^'&[s&'?sJ'&]
                  @>a^'&            All but 1st char of match, split on &
                FI                  Filter on this function:
   _@`^[^=]+`                         Regex match: run of non = from beginning of string
                                      @ returns a list (here, of one item), so...
  J                                   Join to get a scalar
             NIy                      True if match not in y; false if in y
s:                                  Assign the filtered list to s
                        [        ]  Return a list containing:
                         s&'?       ? if s is nonempty, [] otherwise
                             sJ'&   s joined on &
                                    When used as a replacement, a list is first stringified
                                    (which, in the absence of flags, means concatenated)

1

PowerShell v3 +, 115 90 byte

param($n,$z)$a,$b=$n-split'\?';($z|%{$b=$b-replace"(^|&)$_(=[^&]*)?(&|$)"});$a+"?"*!!$b+$b

Lấy đầu vào $nlà URL và $zdưới dạng một chuỗi ký tự bằng chữ làm tham số cần loại bỏ. -splits URL đầu vào trên ?, lưu trữ nửa đầu vào $avà thứ hai vào $b.

Tiếp theo, $bđược xây dựng lại bằng cách thực hiện một vòng lặp $z, thực hiện một biểu thức chính -replacetrên mỗi từ truy vấn bị cấm để loại bỏ chúng. Sau đó, các kết quả đầu ra $a(không được sửa đổi), cộng với /tùy thuộc vào việc có $btồn tại hay không , cộng với ?tùy thuộc vào việc có $xtồn tại hay không , cộng với `$ x.


1

Pyth - 27 byte

Kenny đã đúng khi nói về việc dựng sẵn để biến đổi và sau đó đảo ngược, mặc dù vậy, sẽ rất khó để đúng.

.sjK\?mj\&f!}hcT\=Qcd\&czKK

Phòng thử nghiệm .


1

Võng mạc , 44 48 byte

Crossed-out 44 vẫn là 44. Cảm ơn Martin đã sửa chữa.

[?&](?>([^ =&]+))[^ &]*(?=.* \1( |$))| .*

/&
/?

Đưa đầu vào như thế nào uri param1 param2. Hãy thử trực tuyến!

Giải trình

Sự thay thế đầu tiên xóa các tham số thích hợp khỏi chuỗi truy vấn. [?&](?>([^ =&+))[^ &]*khớp với một ?hoặc &, một tên tham số đầy đủ và (tùy chọn) =và một giá trị, lưu trữ tên tham số trong nhóm chụp 1. Sau đó, (?=.* \1( |$))một cái nhìn sẽ kiểm tra xem tên tham số đó có xuất hiện trong danh sách các tham số cần xóa hay không. Nếu một tham số phù hợp với các điều kiện này, nó sẽ bị xóa (thay thế bằng một thay thế trống).

Thay thế là không chồng chéo (nhờ vào cái nhìn) và tiến hành từ trái sang phải. Khi đến cuối URL, .*chi nhánh khớp với danh sách các tham số cần xóa và cũng xóa nó.

Sự thay thế thứ hai chỉ đảm bảo chuỗi truy vấn mới bắt đầu bằng ?nếu tham số đầu tiên bị xóa.


Tôi nghĩ rằng điều này cũng loại bỏ các tham số nếu một tiền tố của chúng xuất hiện trong danh sách ở cuối (ví dụ: thử retina.tryitonline.net/ .). Một cách để khắc phục điều này là bọc nhóm 1 trong (?>...).
Martin Ender

@MartinEnder TIL về các biểu hiện phụ không quay lại. Cảm ơn!
DLosc

0

Java 7, 203 byte

String f(String u,List p)throws Exception{String[]g=u.split("\\?",2);String s="";if(g.length>1)for(String q:g[1].split("&")){if(p.indexOf(q.split("=")[0])<0){s+=s.isEmpty()?"?":"&";s+=q;}}return g[0]+s;}

Ung dung:

  String f(String u, List p) throws Exception {
    String[] g = u.split("\\?", 2);
    String s = "";
    if (g.length > 1) for (String q : g[1].split("&")) {
      if (p.indexOf(q.split("=")[0]) < 0) {
        s += s.isEmpty() ? "?" : "&";
        s += q;
      }
    }
    return g[0] + s;
  }

Hàm này vượt qua tất cả các bài kiểm tra.



0

PHP, không cạnh tranh

Heck, PHP đã được thực hiện cho điều này; Tại sao không sử dụng URL thực tế?

<?foreach($_GET[x]as$w)unset($_GET[$w]);
echo http,s[$_SERVER[SERVER_PORT]-443],"://",
$u=$_SERVER[PHP_AUTH_USER],($p=$_SERVER[PHP_AUTH_PW])?":$p":"","@"[!$u&!$p],
"$_SERVER[HTTP_HOST]$_SERVER[SCRIPT_NAME]?",http_build_query($_GET);

Lưu vào tập tin, gọi với chuỗi truy vấn mong muốn của bạn cộng &x[]=x&x[]=<exclude1>&x[]=<exclude2>&....

Có thể thất bại về tên người dùng và mật khẩu (tùy thuộc vào thời tiết trình duyệt của bạn có xóa chúng hay không).
Sẽ thất bại nếu mật khẩu là 0.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.