一行目に base と n が空白一つで区切って与えられる(1 ≤ n ≤ 100)。 base は空白を含まない 1~50 文字の文字列で、変換せずそのまま使う。 続く n 行に条件が一行ずつ与えられる。 名前は英小文字 1~10 文字である。 値は 1~100 文字で、コード 32~126 の文字(空白、英字、数字、記号)だけからなり、空白で始まったり終わったりしない。
出力
完成したリンク一行
例 1 · stdin
https://shop.example/search 4
q red shoes & socks
page
sort price_asc
tag 50%/off!
from urllib.parse import quotebase, n = input().split()pairs = []for _ in range(int(n)): # 처음 나오는 빈칸에서만 자른다. 빈칸이 없으면 value는 빈 문자열이다 name, _, value = input().partition(" ") if value == "": continue # quote는 기본으로 "/"를 그대로 둔다. safe=""로 그것도 바꾸게 한다 pairs.append(name + "=" + quote(value, safe=""))# 조각을 목록에 모았다가 join으로 한 번에 잇는다: 사이에만 "&"가 들어간다print(base + ("?" + "&".join(pairs) if pairs else ""))
JavaScriptmain.js · 19 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const [base, n] = lines[0].split(" ");// encodeURIComponent는 ! ' ( ) * 다섯 글자를 그대로 둔다. 그 다섯 글자는 따로 바꾼다function encode(value) { return encodeURIComponent(value).replace( /[!'()*]/g, (c) => "%" + c.charCodeAt(0).toString(16).toUpperCase() );}const pairs = [];for (let i = 1; i <= Number(n); i++) { const line = lines[i]; const at = line.indexOf(" "); // split(" ", 2)는 셋째 조각부터 버리므로 쓰지 않는다 if (at === -1) continue; pairs.push(line.slice(0, at) + "=" + encode(line.slice(at + 1)));}console.log(base + (pairs.length > 0 ? "?" + pairs.join("&") : ""));
TypeScriptmain.ts · 20 行
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const [base, n] = lines[0].split(" ");// encodeURIComponent는 ! ' ( ) * 다섯 글자를 그대로 둔다. 그 다섯 글자는 따로 바꾼다function encode(value: string): string { return encodeURIComponent(value).replace( /[!'()*]/g, (c: string) => "%" + c.charCodeAt(0).toString(16).toUpperCase() );}const pairs: string[] = [];for (let i = 1; i <= Number(n); i++) { const line = lines[i]; const at = line.indexOf(" "); // split(" ", 2)는 셋째 조각부터 버리므로 쓰지 않는다 if (at === -1) continue; pairs.push(line.slice(0, at) + "=" + encode(line.slice(at + 1)));}console.log(base + (pairs.length > 0 ? "?" + pairs.join("&") : ""));
JavaMain.java · 36 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;public class Main { // URLEncoder.encode는 빈칸을 +로 바꾸고 ~를 바꿔 버려서 규칙과 다르다. 그래서 직접 만든다 static void appendEncoded(StringBuilder out, String value) { for (int i = 0; i < value.length(); i++) { char c = value.charAt(i); boolean keep = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '_' || c == '.' || c == '~'; if (keep) { out.append(c); } else { out.append(String.format("%%%02X", (int) c)); // %% 는 % 한 글자, %02X는 대문자 16진수 두 자리 } } } public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String[] first = in.readLine().split(" "); int n = Integer.parseInt(first[1]); StringBuilder out = new StringBuilder(first[0]); boolean any = false; for (int i = 0; i < n; i++) { String[] parts = in.readLine().split(" ", 2); // 많아야 두 조각: 둘째 조각에 나머지가 모두 남는다 if (parts.length < 2) continue; out.append(any ? '&' : '?'); // 첫 쌍 앞에는 ?, 그다음부터는 & any = true; out.append(parts[0]).append('='); appendEncoded(out, parts[1]); } System.out.println(out); }}
C#Main.cs · 20 行
using System;using System.Collections.Generic;class Program{ static void Main() { string[] first = Console.ReadLine().Split(' '); int n = int.Parse(first[1]); var pairs = new List<string>(); for (int i = 0; i < n; i++) { string[] parts = Console.ReadLine().Split(' ', 2); // 많아야 두 조각: 둘째 조각에 나머지가 모두 남는다 if (parts.Length < 2) continue; // Uri.EscapeDataString은 영문자·숫자와 - _ . ~ 만 남기고 %XX(대문자)로 바꾼다 pairs.Add(parts[0] + "=" + Uri.EscapeDataString(parts[1])); } Console.WriteLine(first[0] + (pairs.Count > 0 ? "?" + string.Join("&", pairs) : "")); }}
C++main.cpp · 36 行
#include <iostream>#include <string>int main() { std::string base; int n; std::cin >> base >> n; std::string line; std::getline(std::cin, line); // 첫 줄의 나머지(줄바꿈)를 넘긴다 const std::string hex = "0123456789ABCDEF"; std::string out = base; // std::string은 += 로 뒤에 이어 붙여도 빠르다 bool any = false; for (int i = 0; i < n; i++) { std::getline(std::cin, line); auto at = line.find(' '); // 처음 나오는 빈칸 if (at == std::string::npos) continue; out += any ? '&' : '?'; any = true; out += line.substr(0, at); out += '='; for (std::size_t k = at + 1; k < line.size(); k++) { char c = line[k]; bool keep = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '_' || c == '.' || c == '~'; if (keep) { out += c; } else { out += '%'; out += hex[c / 16]; // 16진수 윗자리 out += hex[c % 16]; // 16진수 아랫자리 } } } std::cout << out << '\n';}
Cmain.c · 30 行
#include <ctype.h>#include <stdio.h>#include <string.h>int main(void) { char base[64]; int n; scanf("%63s %d", base, &n); getchar(); /* 첫 줄 끝의 줄바꿈을 넘긴다 */ fputs(base, stdout); int any = 0; char line[160]; for (int i = 0; i < n; i++) { if (!fgets(line, sizeof line, stdin)) break; line[strcspn(line, "\n")] = '\0'; char *space = strchr(line, ' '); /* 처음 나오는 빈칸 */ if (space == NULL) continue; *space = '\0'; /* 그 자리에서 이름과 값을 끊는다 */ /* C에서는 문자열을 이어 붙이는 대신 조각을 바로바로 출력한다 */ printf("%c%s=", any ? '&' : '?', line); any = 1; for (const char *p = space + 1; *p != '\0'; p++) { unsigned char c = (unsigned char)*p; if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') putchar(c); else printf("%%%02X", (unsigned)c); /* %X는 대문자, %x는 소문자 16진수 */ } } putchar('\n'); return 0;}
Craykonmain.cray · 45 行
십육진수 = "0123456789ABCDEF";// 값의 글자를 하나씩 보고, 그대로 둘 글자가 아니면 %와 16진수 두 자리로 바꾼다바꾸기값(값){ 결과 = ""; それぞれ (c の中 값) { 그대로 = c >= "A" && c <= "Z" || c >= "a" && c <= "z" || c >= "0" && c <= "9" || c == "-" || c == "_" || c == "." || c == "~"; もし (그대로) { 결과 = 결과 + c; } でなければ { 코드 = 文字.コード(c); 결과 = 결과 + "%" + 십육진수[数学.商(코드, 16)] + 십육진수[코드 % 16]; } } 返す 결과;}첫줄 = コンソール.行読み().分ける(" ");n = 첫줄[1].数に();쌍들 = [];繰り返す (i = 0; i < n; i++){ 줄 = コンソール.行読み(); 자리 = 줄.位置検索(" "); // 처음 나오는 빈칸, 없으면 -1 もし (자리 == -1) { 次へ; } 이름 = 줄.切り出す(0, 자리); 값 = 줄.切り出す(자리 + 1, 줄.長さ - 자리 - 1); 쌍들.追加(이름 + "=" + 바꾸기값(값));}もし (쌍들.個数 > 0){ コンソール.書く(첫줄[0] + "?" + 쌍들.つなぐ("&"));}でなければ{ コンソール.書く(첫줄[0]);}