쿼리 자르기


19

나는 당신이 항상 웹 프록시로서 인생의 기쁨을 경험하는 시련과 고난에 대해 생각했다는 것을 알고 있습니다. 솔직히 누가하지 않았습니까? 오늘 당신은이 목표 (적어도 그 일부)를 실현해야합니다. 웹 사이트 X는 매일 많은 트래픽을 발생 시키며 쿼리 매개 변수를 통해 민감한 정보를 전달해야하는 많은 수의 사용자 (사용자는 어리 석음)로 인해 PaaS (Proxy as a Service)를 찾고 있습니다. 귀하의 작업은 요청을 원래 대상으로 전달하기 전에 요청에서 중요한 쿼리 매개 변수를 모두 제거하는 것입니다.

입력

  • 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
&매개 변수 이외의 다른 곳에 나타날 수 있습니까 ?
라일리

예를 들어 비밀번호에 ?? 또한 주문을 그대로 유지해야합니까?
KarlKastor

@Riley No. &검색어 매개 변수의 일부인 경우 다음 과 같이 올바르게 표시되어야합니다.%26
Poke

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 바이트 차이입니다.
Riley

편집 기록에 96, 77 및 59 바이트 코드 버전이 없습니다. 편집 7 제목은 편집 6에 비해 10 바이트가 적었지만 코드는 변경되지 않았습니다. 나는 nitpicking 해요, 훌륭한 골프!
seshoumara

1
@seshoumara 나는 약간의 문자를 삭제하기 때문에 일부 편집 내용을 결합했다고 생각합니다.
라일리

@seshoumara 나는 서로 5 분 이내에 여러 번 편집했기 때문에 실제로 결합한 것 같습니다.
라일리

5

자바 스크립트 (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

@Shaggy 문자열을 반환하지 않을 것입니다 ... 허용되지 않는다고 가정했습니다.
Neil

출력 방법에 따라 다릅니다. 예를 들어, alert(텍스트) 노드에 삽입하거나 사용 href하는 경우 객체 의 속성을 제공 합니다. 콘솔에 로그인하면 전체 객체를 제공합니다. 이 바이올린을 참조하십시오 .
Shaggy

1
@ Shaggy Ah, 그래서 2 바이트를 문자열 화하여 확실히 절약 할 수 있습니다. 감사합니다.
Neil

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 바이트 : 대안은 괄호로 묶어야하거나 ^/ (.*|$)는 첫 번째 / 마지막 대안의 일부입니다.
Titus

-2 바이트 : remove .*. 또는 교체 (=.*|$)하여 \b(-5).
Titus

귀하의 정규 표현식은 모양을 #^foo|bar(=.*|$)#한이 동일합니다 #(^foo)|(bar=.*|bar$))#. 그러나이어야합니다 #(foo|bar)(=.*|$)#.
Titus

@Titus 당신은 내 잘못이야
Jörg Hülsermann

좋은! 나는 단언을 생각하지 않았다. 그렇기 때문에 제가 다시 돌아 왔습니다 array_map(그리고 그것이 얼마나 짧을 수 있는지 놀랐습니다).
Titus

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_str? http_build_query? 코드 골프에서도 작업에 적합한 도구를 사용하여 작업하는 사람을 보게되어 기쁩니다. URL / SQL 쿼리 / regexp / HTML로 인해 발생하는 버그는 "단지 문자열"이므로 쉽게 예방할 수 있습니다.
Daerdemandt

더 많은 영감을 얻을 수 있습니다. 나는 당신을 얻었다
Jörg Hülsermann

@Lynn 스토킹보다 더 좋은 게 없습니까?
Titus

2

자바 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 4를 사용하고 있지만 4, 5, 6 및 9 번째 예제를 사용하면 실패합니다. C #과 동등한 것을 시도했지만 동일한 경우에 실패 했으므로 idunno.
Yodle

1
신경 쓰지 마, 내가 테스트하는 방식을 엉망으로 만들었습니다.
Yodle

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

Ungolfed 전체 프로그램 :

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 바이트 솔루션이 있습니다. 그러나 Regex에 대한 가져 오기가 필요하므로 더 짧을 수는 없습니다.

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 바이트를 저장
당량 인라인 변화 (정규식 재구성에 의해 저장된 3 바이트 편집 4를 $*[1][/([^?]*)\??(.*)/,1]넣고 에 할당 된대로 a)
편집 5 : ($*[2].scan(r=/\w+/)&[x[r]])[0]대신 에 사용하여 3 바이트 저장$*[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 $ 1을 가리키고 b배열의 배열로 구문 분석 합니다.

.reject { |x|

... 거기 거부 ...

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

... 우리가 (목록을 가져올 수) 단어를 검색하기 때문에 그 전에 단어를 얻을이 작품 ... '='두 번째 매개 변수에 의해 주어진 이름의 목록에 포함되어 그 전에 문자열을 =하고 있는지 그 단어는 목록에 &있습니다. &"찾을 수 없음"(널 세트)에서 빈 배열을 반환 하므로 아래 설명 된 트릭을 사용 nil하여 배열에 요소가 없는지 확인합니다. 그렇지 않으면 우리는 문자열을 반환하는데,이 문자열은 진실로 간주되어 해당 문자열을 거부합니다.

}*"&"

... 그리고 나머지 문자열을 '&'와 함께 결합하십시오.

이 시점 b에서 URL에 대한 GET 쿼리 문자열입니다. 따라서 인쇄 만하면됩니다.

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

이것은 루비의 트릭을 사용합니다. b[0]nil, b는 빈 배열 또는 스트링 인 경우. 따라서 진실nil 하거나 (아님 false) 아닌 경우 배열에 하나 이상의 요소가 있으므로 a+"?"+b올바른 URL을 입력 해야합니다 . 그렇지 않으면 a표시 할 매개 변수가 없기 때문에을 넣습니다 .

참고 :이 답변은 쿼리에서 URL을 구분하는 것을 제외하고는 어디에도 나타날 ? 수 없다고 가정 합니다. (연결된 RFC에서 읽은 내용에 따라)

또한 이것은 내 첫 번째 골프 답변입니다 : D


2
PPCG에 오신 것을 환영합니다!
acrolith

1

, 46 바이트

명령 행 인수에서 제거하기 위해 stdin에서 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

입력 을 제거 할 매개 변수로 $nURL 및 $z리터럴 문자열 배열로 사용합니다. -split입력 URL을 on으로 ?, 첫 번째 반을에 저장 $a하고 두 번째를에 저장합니다 $b.

다음으로, $b루프 스루 $z를 수행하여 -replace금지 된 각 쿼리 단어에 대해 정규식 을 수행하여 이를 제거하여 다시 공식화됩니다 . 그런 다음 출력 $a(수정되지 않음)과 존재 /여부에 따른 $b추가, 존재 ?여부에 따른 $x추가 플러스`$ x.


1

Pyth-27 바이트

케니가 내장과 변형을 거꾸로 한 것에 대해 이야기했을 때 옳았지만, 올바른 것은 매우 어려울 것입니다.

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

테스트 스위트 .


1

레티 나 , 44 48 바이트

44가 여전히 44입니다. 수정을위한 Martin에게 감사합니다.

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

/&
/?

같은 입력을 uri param1 param2받습니다. 온라인으로 사용해보십시오!

설명

첫 번째 교체는 쿼리 문자열에서 적절한 매개 변수를 삭제합니다. 캡처 그룹 1에 매개 변수 이름을 저장하는 [?&](?>([^ =&+))[^ &]*a ?또는 &전체 매개 변수 이름 및 (선택적) =값과 일치합니다 . 그런 다음 (?=.* \1( |$))삭제할 매개 변수 목록에 해당 매개 변수 이름이 나타나는지 확인하는 미리보기입니다. 매개 변수가 이러한 조건과 일치하면 제거됩니다 (빈 교체로 대체 됨).

대체는 겹치지 않으며 (lookahead 덕분에) 왼쪽에서 오른쪽으로 진행됩니다. URL 끝에 도달하면 .*브랜치는 삭제할 매개 변수 목록과 일치하여 삭제합니다.

두 번째 교체 ?는 첫 번째 매개 변수가 삭제 된 경우 새 쿼리 문자열로 시작하도록 합니다.


접두사가 끝에 목록에 나타나면 매개 변수도 제거한다고 생각합니다 (예 : retina.tryitonline.net/… ). 이 문제를 해결하는 한 가지 방법은 그룹 1을로 묶는 것입니다 (?>...).
마틴 엔더

역 추적이 아닌 하위 표현식에 대한 @MartinEnder TIL. 감사!
DLosc

0

자바 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

파이썬, 75 81112 바이트 :

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

명명 된 함수. 형식으로 입력을받습니다

D(<String>,<Array>)

문자열을 출력합니다.

모든 테스트 사례와 함께 Repl.it!


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.