Memotong Kueri

19

Saya tahu Anda selalu memikirkan cobaan dan kesengsaraan karena mengalami sukacita hidup sebagai proxy web. Jujur, siapa yang belum? Hari ini Anda ditugaskan untuk mewujudkan tujuan ini (setidaknya sebagian darinya). Situs web X mendapatkan banyak lalu lintas setiap hari dan mencari PaaS (jelas ini merujuk pada Proxy sebagai Layanan) karena sejumlah besar pengguna yang bersikeras meneruskan informasi sensitif melalui parameter kueri (pengguna konyol). Tugas Anda adalah menghapus sebagian dan semua parameter kueri sensitif dari permintaan sebelum meneruskan permintaan hingga ke tujuan awalnya.

Memasukkan

  • URL HTTP absolut yang terbentuk dengan baik mengikuti tata bahasa URI di RFC3986 Bagian 3 .
    • Anda dapat mengasumsikan tidak ada fragmen
    • Contoh format singkat di mana apa pun dalam kurung siku menunjukkan opsional: http[s]://[user:pass@]host.name.com[:port]/[?param1=value1&param2=value2...]
  • Daftar parameter kueri yang akan dihapus.

Keluaran

URL HTTP yang dimodifikasi tanpa parameter yang ditentukan dalam daftar input.

Contohnya

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:[email protected]:8080/?foo=1&bar=foo [foo]
> http://foo:[email protected]:8080/?bar=foo

Mencetak gol

Ini adalah , jadi jawaban tersingkat (dalam byte) menang.

Menyodok
sumber
1
Bisakah saya mendapatkan URL dan parameter kueri masing-masing pada baris yang berbeda?
seshoumara
1
Bisakah &muncul di mana saja selain antar parameter?
Riley
juga dapatkah mis. kata sandi berisi ?? Juga haruskah pesanan tetap seperti itu?
KarlKastor
@Riley No. Jika &merupakan bagian dari parameter kueri, URL harus dimasukkan dengan benar sebagai%26
Poke
1
Rupanya, http://foo:&[email protected]:8080/?foo=1&bar=foodiizinkan oleh RFC. Ini harus memecahkan banyak solusi yang ada. : D (Aturannya adalah userinfo dapat diperluas sebagai unreserved atau pct-escape atau sub-delims, dan sub-delims dapat memiliki &dan =)
n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳

Jawaban:

6

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

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

Daftar parameter untuk dihapus dipisahkan oleh spasi.

$ 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/
Riley
sumber
Dalam pengeditan kode Anda saat ini, beberapa pengujian dari pertanyaan OP memberikan trailing &atau ?karakter di URL yang dihasilkan.
seshoumara
@seshoumara Saya tidak yakin bagaimana saya melewatkan itu ... Untungnya itu hanya perbedaan 1 byte.
Riley
Versi kode 96, 77 dan 59 byte tidak ditemukan dalam riwayat edit Anda. Sunting 7 judul menunjukkan 10 byte lebih sedikit dibandingkan dengan sunting 6, tetapi kode tidak diubah. Saya nitpicking, golf bagus!
seshoumara
1
@seshoumara Saya pikir itu menggabungkan beberapa pengeditan karena mereka kecil (hanya menghapus beberapa karakter).
Riley
@seshoumara Saya kira itu benar-benar menggabungkan mereka karena saya membuat beberapa pengeditan dalam waktu 5 menit satu sama lain.
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>

Sunting: Disimpan 2 byte berkat @Shaggy.

Neil
sumber
Anda dapat menyimpan 5 byte dengan menjatuhkannya .hrefdi akhir.
Shaggy
@Shaggy Itu tidak akan mengembalikan string ... Saya berasumsi itu tidak diizinkan.
Neil
Tergantung bagaimana Anda menghasilkannya. Misalnya, jika Anda alertatau gunakan masukkan ke dalam simpul (teks), seperti yang Anda miliki, itu akan memberi Anda hrefproperti objek. Jika Anda login ke konsol, itu akan memberi Anda objek lengkap. Lihat biola ini .
Shaggy
1
@ Shaggy Ah, jadi saya pasti bisa menghemat 2 byte dengan menggantinya, terima kasih.
Neil
3

PHP, 90 Bytes

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

-11 Bytes jika? atau & diizinkan di bagian akhir

Versi Sebelumnya 140 Bytes

<?=substr($u=$_GET[u],0,strpos($u,"?")+!!$j=join("&",preg_grep("#^(".join("|",$_GET[r]).")(=|$)#",explode("&",parse_url($u)[query]),1))).$j;
Jörg Hülsermann
sumber
+2 byte: Alternatif harus di-kurung, atau ^/ (.*|$)akan menjadi bagian dari alternatif pertama / terakhir.
Titus
-2 byte: hapus .*. atau ganti (=.*|$)dengan \b(-5).
Titus
Regexp Anda akan terlihat seperti #^foo|bar(=.*|$)#yang identik dengan #(^foo)|(bar=.*|bar$))#. Tapi seharusnya begitu #(foo|bar)(=.*|$)#.
Titus
@Titus Kamu benar salahku
Jörg Hülsermann
bagus! Saya tidak memikirkan pernyataan; itu sebabnya saya jatuh kembali ke array_map(dan saya terkejut betapa pendeknya itu bisa berubah).
Titus
2

PHP, 120 110 byte

dengan fungsi preg_replace dan array: (terinspirasi oleh Jörg )

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

simpan ke file, panggil dengan php <scriptname> <uri> <parametername> <parametername> ...

dengan parse_str dan 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);

jalankan bersama php -r <code> <uri> <parametername> <parametername> ...

Titus
sumber
parse_str? http_build_query? Saya sangat senang melihat seseorang bekerja menggunakan alat yang tepat untuk pekerjaan itu, bahkan dalam kode golf. Bug yang muncul karena URL / kueri SQL / regexp / HTML adalah "hanya string" yang jumlahnya banyak karena mudah dicegah.
Daerdemandt
Mungkin untuk inspirasi lebih banyak. Saya mendapatkan Anda
Jörg Hülsermann
@ Lynn Tidakkah Anda memiliki sesuatu yang lebih baik untuk dilakukan daripada menguntit saya?
Titus
2

Java 7, 127 byte

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

Penjelasan

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

Ideone

Menyodok
sumber
Ini gagal bagi saya menggunakan contoh ke-4, ke-5, ke-6, dan ke-9 oO Saya menggunakan Java 8, jadi bisa jadi itu. Meskipun mencoba setara C # dan gagal kasus yang sama, jadi idunno.
Yodle
1
Nevermind, mengacaukan cara saya mengujinya.
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;}

Program lengkap tidak digabungkan:

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

Mungkin tidak terlalu efisien, tetapi saya pikir itu berhasil.

Atau, ada solusi 173 byte menggunakan metode @ Poke dari Java. Membutuhkan impor untuk Regex, jadi mungkin tidak bisa lebih pendek.

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

Ruby, 146 140 127 119 116 113 byte

sunting 2: disimpan 6 byte dengan menggunakan $1,, $2dan $*, dan 7 dengan mengubah x.split("=")[0]ke x[/\w+/]
edit 3: disimpan 6 byte dengan menggunakan *alih-alih .join, disimpan 2 byte dari ruang yang tidak perlu
edit 4: disimpan 3 byte dengan memformulasikan inline (ubah regex menjadi setara $*[1][/([^?]*)\??(.*)/,1]dan masukkan seperti yang ditugaskan pada a)
edit 5: disimpan 3 byte dengan menggunakan ($*[2].scan(r=/\w+/)&[x[r]])[0]alih-alih$*[2].scan(r=/\w+/).include?(x[r])

Dengan asumsi input ke program saat menjalankannya:

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

Penjelasan

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

Ini mem-parsing URL yang diberikan pada baris perintah, dan menyimpan kecocokan ke dalam $1dan $2. $*[1][/([^?]*)\??(.*)/,1]juga mengembalikan pertandingan pertama untuk disimpan di dalam a, sedangkan pertandingan kedua disebut sebagai $2 membiarkan poin menjadi $ 1, dan menguraikan bke dalam array array ...

.reject { |x|

... menolak semua itu ...

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

... punya string sebelum '=' yang termasuk dalam daftar nama yang diberikan oleh parameter kedua ... Ini berfungsi karena kita memindai kata-kata (untuk mendapatkan daftar) kemudian mendapatkan kata sebelum =, dan melihat apakah kata itu ada dalam daftar &. Karena &mengembalikan array kosong pada "not found" (set nol), kami menggunakan trik yang dijelaskan di bawah ini untuk mendapatkan niljika tidak ada elemen dalam array. kalau tidak, kita mengembalikan string, yang dianggap benar, yang menolak string itu.

}*"&"

... dan bergabung dengan string yang tersisa bersama dengan '&'

Pada titik ini, bdapatkan string kueri GET untuk URL. Jadi, kita hanya perlu mencetaknya.

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

Ini menggunakan trik di ruby. b[0]akan menjadi niljika b adalah array atau string kosong. Jadi jika truthy , (tidak nilatau false), maka ada setidaknya satu elemen dalam array, jadi kita perlu menempatkan a+"?"+buntuk URL yang benar. jika tidak, kami hanya menempatkan a, karena tidak ada parameter untuk ditampilkan

Catatan: jawaban ini mengasumsikan bahwa ? tidak dapat muncul di mana pun kecuali untuk membatasi URL dari kueri. (sesuai dengan apa yang saya baca dari RFC yang tertaut)

Juga, ini jawaban golf pertama saya: D

Nerketur Kamachi
sumber
2
Selamat datang di PPCG!
acrolith
1

Pip , 46 byte

Mengambil URL dari stdin dan parameter kueri untuk dihapus dari argumen baris perintah.

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

Cobalah online!

Penjelasan:

 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)
DLosc
sumber
1

PowerShell v3 +, 115 90 byte

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

Mengambil input $nsebagai URL dan $zsebagai array string secara literal sebagai parameter untuk dihapus. -splits pada input URL aktif ?, simpan bagian pertama masuk $adan kedua masuk $b.

Selanjutnya, $bdirumuskan ulang dengan mengambil loop melalui $z, melakukan regex -replacepada setiap kata permintaan yang dilarang untuk menghapusnya. Kemudian, output $a(tidak dimodifikasi), ditambah /tergantung pada apakah $bada, ditambah ?tergantung pada apakah $xada, ditambah `$ x.

AdmBorkBork
sumber
1

Pyth - 27 byte

Kenny benar ketika dia berbicara tentang builtin untuk diubah dan kemudian membalikkan, itu akan sangat sulit untuk diluruskan.

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

Test Suite .

Maltysen
sumber
1

Retina , 44 48 byte

Crossed-out 44 masih 44. Terima kasih kepada Martin untuk perbaikannya.

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

/&
/?

Mengambil input seperti uri param1 param2. Cobalah online!

Penjelasan

Penggantian pertama menghapus parameter yang sesuai dari string kueri. [?&](?>([^ =&+))[^ &]*cocok dengan ?atau &, nama parameter lengkap, dan (opsional) =dan nilai, menyimpan nama parameter dalam grup tangkap 1. Kemudian (?=.* \1( |$))adalah lookahead yang memeriksa apakah nama parameter itu muncul dalam daftar parameter yang akan dihapus. Jika parameter cocok dengan kondisi ini, itu dihapus (diganti dengan pengganti kosong).

Substitusi adalah non-tumpang tindih (terima kasih kepada lookahead) dan lanjutkan dari kiri ke kanan. Saat mencapai akhir URL, .*cabang cocok dengan daftar parameter untuk dihapus dan dihapus juga.

Penggantian kedua hanya memastikan string kueri baru dimulai dengan ?jika parameter pertama dihapus.

DLosc
sumber
Saya pikir ini juga menghapus parameter jika awalan dari mereka muncul di daftar di akhir (mis. Coba retina.tryitonline.net/... ). Salah satu cara untuk memperbaikinya adalah dengan membungkus grup 1 (?>...).
Martin Ender
@MartinEnder TIL tentang subekspresi yang tidak dapat dilacak kembali. Terima kasih!
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;}

Tidak Disatukan:

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

Fungsi ini melewati semua tes.

akrolit
sumber
0

Python, 75 81 112 byte:

def Z(A,S):import re;F=A.rindex('/');print A[:F]+re.sub('|'.join(i+'(=\d?|&)&?'for i in S),'',A[F:]).strip('&?')

Fungsi bernama. Mengambil input dalam format

D(<String>,<Array>)

dan menghasilkan string.

Repl.it Dengan Semua Kasus Uji!

R. Kap
sumber
0

PHP, tidak bersaing

Heck, PHP dibuat untuk ini; mengapa tidak menggunakan URL yang sebenarnya?

<?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);

Simpan ke file, panggil dengan string kueri yang Anda inginkan plus &x[]=x&x[]=<exclude1>&x[]=<exclude2>&....

Mungkin gagal pada nama pengguna dan kata sandi (tergantung apakah browser Anda menghapusnya atau tidak).
Akan gagal jika kata sandi 0.

Titus
sumber