クエリの活用


19

私はあなたがウェブプロキシとして人生の喜びを体験することの試練と苦難について常に考えてきたことを知っています。正直なところ、誰がそうではありませんか?今日、あなたはこの目標(少なくともその一部)の実現を任されています。WebサイトXは、クエリパラメーターを介して機密情報を渡すことを要求する多数のユーザーのために、毎日多くのトラフィックを獲得し、PaaS(明らかにサービスとしてのプロキシを指します)を探しています(ユーザーは愚かです)。あなたのタスクは、リクエストを元の宛先に転送する前に、リクエストからすべての重要なクエリパラメータを削除することです。

入力

  • RFC3986セクション3の URI文法に従う、整形式の絶対HTTP URL 。
    • フラグメントがないと仮定できます
    • 角括弧で囲まれたものがオプションを示す簡単な形式の例: http[s]://[user:pass@]host.name.com[:port]/[?param1=value1&param2=value2...]
  • 削除するクエリパラメータのリスト。

出力

入力リストにパラメーターが定義されていない、変更されたHTTP URL。

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

得点

これはなので、最短の回答(バイト単位)が優先されます。


1
URLとクエリパラメータを別々の行に取得できますか?
seshoumara

1
&パラメーター間以外に表示できますか?
ライリー

たとえば、パスワードに??を含めることもできます。また、注文は以前のように保持する必要がありますか?
カールカストール

@Rileyいいえ。&クエリパラメータの一部である場合は、次のように正しくエンコードする必要があります%26
ポケ

1
どうやら、http://foo:&foo=x@foo.com:8080/?foo=1&bar=fooRFCによって許可されています。これは、既存のソリューションの束を壊すはずです。:D(ルールは、ユーザー情報で予約されていないか、PCTエスケープまたはサブdelimsとして展開することができ、サブdelimsを有することができる&=
n̴̖̋h̷͉a̷̭̿h̸̡̅ẗ̵̨d̷̰ĥ̷̳

回答:


6

GNU sed 98 96 88 80 77 74 69 59 54(-rの場合は48 + 1)49

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

削除するパラメーターのリストはスペースで区切ります。

$ 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/

現在のコード編集では、OPの質問からの複数のテストにより、結果のURLの末尾&または?文字が示されます。
seshoumara

@seshoumaraどうしてそれを見逃したのかわかりません...幸いなことに、それはたった1バイトの違いです。
ライリー

96、77、および59バイトコードバージョンは、編集履歴に見つかりません。編集7のタイトルは、編集6と比較して10バイト少なく表示されていましたが、コードは変更されていませんでした。でも、ピッキングは最高です、素晴らしいゴルフです!
seshoumara

1
@seshoumaraいくつかの編集がマイナーであるため(いくつかの文字を削除するだけ)、編集の一部を組み合わせたと思います。
ライリー

@seshoumara互いに5分以内に複数の編集を行ったため、実際にそれらを結合したと思います。
ライリー

5

JavaScript(ES6)、62 60バイト

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>

編集:@Shaggyのおかげで2バイト保存されました。


.href最後にをドロップすると、5バイト節約できます。
シャギー

@Shaggyそれは文字列を返しません...私はそれが許可されていないと仮定していました。
ニール

出力方法によって異なります。たとえば、それをalert使用する場合、または使用して(テキスト)ノードに挿入するとhref、オブジェクトのプロパティが提供されます。ただし、コンソールにログを記録すると、完全なオブジェクトが得られます。このFiddleを参照してください。
シャギー

1
@Shaggy Ah、文字列化することで間違いなく2バイト節約できます、ありがとう。
ニール

3

PHP、90バイト

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

-11バイトの場合?または&は最後に使用できます

以前のバージョン140バイト

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

+2バイト:選択肢は括弧で囲む必要があります。そうでない場合、^/ (.*|$)は最初/最後の選択肢の一部になります。
タイタス

-2バイト:削除します.*または交換(=.*|$)して\b(-5)。
タイタス

あなたの正規表現は次のようになります#^foo|bar(=.*|$)#と同一です#(^foo)|(bar=.*|bar$))#。しかし、そうでなければなりません#(foo|bar)(=.*|$)#
タイタス

@タイタスあなたは私のせいです
ヨルグ・ヒュルサーマン

いいね!私は主張を考えていませんでした。だからこそ、私はそれに立ち戻りましたarray_map(そして、どれほど短いことが判明したのか驚きました)。
タイタス

2

PHP、120 110バイト

preg_replaceおよび配列関数:(Jörgに触発された)

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

ファイルに保存、呼び出し php <scriptname> <uri> <parametername> <parametername> ...

parse_strおよびhttp_build_query(120バイト)の場合:

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

と走る php -r <code> <uri> <parametername> <parametername> ...


parse_strhttp_build_query?コードゴルフでも、誰かが仕事に適したツールを使って働いているのを見てとてもうれしいです。URL / SQL query / regexp / HTMLが「単なる文字列」であるために発生するバグは、簡単に防止できるのと同じくらい多数あります。
-Daerdemandt

より多くのインスピレーションのために。私はあなたを得た
ヨルクヒュルサーマン

@Lynnあなたは私をストーカーすることより良いことはありませんか?
タイタス

2

Java 7、127バイト

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

説明

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

イデオネ


これは、Java 8を使用しているので、4番目、5番目、6番目、および9番目の例を使用すると失敗します。同等のC#を試してみましたが、同じケースで失敗しましたが、idunnoです。
ヨドル

1
気にせず、私がそれをテストしていた方法を台無しにしました。
ヨドル

2

C位、377 336 330 328バイト(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;}

ゴルフされていない完全なプログラム:

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

おそらくあまり効率的ではありませんが、うまくいくと思います。

または、Javaの@Pokeのメソッドを使用した173バイトのソリューションがあります。ただし、正規表現のインポートが必要なため、おそらくこれより短くすることはできません。

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

ルビー、146140127119116113バイト

編集2:使用して、6つのバイトを保存し$1$2および$*変化させることにより、及び7 x.split("=")[0]x[/\w+/]
編集3:使用して、6つのバイトを保存*代わりに.join、不要な空間から2バイト保存
、編集4:インライン改質によって保存された3つのバイトは、(同等に正規表現を変更$*[1][/([^?]*)\??(.*)/,1]し、PUT割り当てられているなどa
を編集5:使用して3つのバイトを保存する($*[2].scan(r=/\w+/)&[x[r]])[0]代わりに、$*[2].scan(r=/\w+/).include?(x[r])

プログラムを実行するときのプログラムへの入力を想定:

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

説明

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

これは、コマンドラインで指定されたURLを解析し、にマッチを格納$1して$2$*[1][/([^?]*)\??(.*)/,1]また、最初の一致を格納して内部に格納しますがa、2番目の一致は$2 $ 1へのポイントを許可bし、配列の配列に解析すると呼ばれます...

.reject { |x|

...すべてを拒否しています...

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

... 2番目のパラメーターで指定された名前のリストに含まれる '='の前に文字列があります...これは、(リストを取得するために)単語をスキャンしてから=、その単語はでリストにあり&ます。以来&返します(空集合)「が見つかりません」の空の配列は、我々は使用トリックは、取得するには、以下に説明するnil配列の要素がない場合。それ以外の場合は、文字列を返しますが、これは真実と見なされ、その文字列は拒否されます。

}*"&"

...残りの文字列を「&」で結合します

この時点で、bはURLのGETクエリ文字列です。したがって、印刷するだけです。

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

これはルビーのトリックを使用します。 b[0]なりますnilbは空の配列や文字列である場合。そのため、その真実性が(nilまたはfalse)ではない場合、配列に少なくとも1つの要素があるa+"?"+bため、正しいURL を配置する必要があります。それ以外の場合、a表示するパラメーターがないため、

注:この回答は、クエリからURLを区切る以外はどこにも表示? できないことを前提としています。(リンクされたRFCから読んだものによる)

また、これは私の最初のゴルフの答えです:D


2
PPCGへようこそ!
アクロリス

1

ピップ、46バイト

標準入力からURLを取得し、コマンドライン引数から削除するためのクエリパラメータを取得します。

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

オンラインでお試しください!

説明:

 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バイト

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

入力$nをURL $zとして、文字列のリテラル配列として、削除するパラメーターとして受け取ります。-splits入力URLをオンにし?、前半を$aに、後半をに保存し$bます。

次に、を$bループして$z-replace禁止されたクエリワードごとに正規表現を実行して削除します。次いで、出力$a(未変性)、プラス/かどうかに応じて$b存在し、プラス?かどうかに応じて$x存在し、プラス`$ X。


1

パイス-27バイト

ケニーは、変換してから反転するビルトインについて話したときは正しかったが、正しいことは非常に難しいだろう。

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

テストスイート


1

網膜44 48バイト

取り消し線44はまだ44です。修正してくれたMartinに感謝します。

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

/&
/?

のような入力を受け取りますuri param1 param2オンラインでお試しください!

説明

最初の置換は、クエリ文字列から適切なパラメーターを削除します。[?&](?>([^ =&+))[^ &]*は、?または&、完全なパラメーター名、および(オプションで)=キャプチャーグループ1にパラメーター名を格納する値に一致します。その後(?=.* \1( |$))、削除するパラメーターのリストにそのパラメーター名が表示されるかどうかを確認する先読みです。パラメーターがこれらの条件に一致する場合、パラメーターは削除されます(空の置換で置換されます)。

置換は重複せず(先読みのおかげで)、左から右に進みます。URLの最後に達すると、 .*ブランチは削除するパラメーターのリストと一致し、同様に削除します。

2番目の置換では?、最初のパラメーターが削除された場合に新しいクエリ文字列が確実に開始されるようにします。


末尾のリストにパラメータのプレフィックスが表示されている場合、これによりパラメータも削除されると思います(たとえば、retina.tryitonline.net /…を試してください)。これを修正する1つの方法は、グループ1をラップすることです(?>...)
マーティンエンダー

@MartinEnder TILの非バックトラッキング部分式について。ありがとう!
DLosc

0

Java 7、203バイト

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

ゴルフをしていない:

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

この関数はすべてのテストに合格します。



0

PHP、競合しない

一体、PHPはこのために作られました。実際のURLを使用しないのはなぜですか?

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

ファイルに保存し、必要なクエリ文字列plusで呼び出します&x[]=x&x[]=<exclude1>&x[]=<exclude2>&...

ユーザー名とパスワードで失敗する場合があります(ブラウザがそれらを削除するかどうかによって異なります)。
ウィルパスワードがある場合には失敗0

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.