웹 주소의 물음표 뒤에 붙는 설정 문자열 한 줄이 주어진다.
설정 문자열은 영어 소문자, 숫자, '=', '&'로만 되어 있다.
먼저 설정 문자열을 '&'로 나눈다.
나눈 조각 가운데 빈 조각은 버린다. 빈 조각은 &가 이어지거나 맨 앞이나 맨 뒤에 &가 있을 때 생긴다.
남은 조각마다, 처음 나오는 '='의 앞이 이름이고 뒤가 값이다.
값에는 '='가 또 들어 있을 수 있고, 값이 빈 문자열일 수도 있다.
'='가 없는 조각은 조각 전체가 이름이고 값은 빈 문자열이다.
어떤 조각도 '='로 시작하지 않는다.
둘째 줄에 질문 수 q가, 다음 q줄에 이름이 하나씩 주어진다.
첫 줄에 남은 조각의 개수를 출력하라.
이어서 질문마다 한 줄에, 그 이름을 가진 조각들의 값을 나온 차례대로 하나씩 대괄호로 감싸 빈칸 없이 이어 출력하라.
값이 빈 문자열이면 []로 출력한다.
그 이름을 가진 조각이 없으면 -를 출력한다.
입력
설정 문자열은 1~10,000글자, 1 ≤ q ≤ 100, 질문한 이름은 영어 소문자와 숫자로 된 1~10글자
출력
첫 줄에 조각의 개수, 다음 q줄에 질문마다 값들 또는 -
예시 1 · stdin
page=2&sort=new&&tag=a&tag=b=c&debug&
4
tag
debug
page
size
stdout
5
[a][b=c]
[]
[2]
-
예시 2 · stdin
&&&
1
a
stdout
0
-
main.py
오류 목록00F8 ↓ · ⇧F8 ↑
입력(stdin)
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이
나누기 함수는 8개 언어에 모두 있지만, 빈 조각과 '나누는 횟수'를 다루는 방식이 저마다 달라요. Python split("&"), JS·TS split("&"), 크레이콘 나누기("&")는 빈 조각을 그대로 남겨서 "&&&"이 빈 문자열 4개가 되니 직접 걸러야 해요. Java split("&")은 정규식으로 나누고, 맨 뒤의 빈 조각만 버리고 맨 앞과 가운데의 빈 조각은 남겨요. C# Split('&', StringSplitOptions.RemoveEmptyEntries)는 빈 조각을 모두 버려요. C strtok은 이어진 &를 하나로 보고 빈 조각을 건너뛰어서 '&' 쪽에는 딱 맞아요. 하지만 '='까지 strtok으로 자르면 "k=="의 값 "="이 사라지니 strchr로 처음 '='만 찾아요. C++의 std::string에는 나누기 함수가 없어서 getline(stream, piece, '&')로 한 조각씩 꺼내고 find('=')로 자르는 게 흔해요. 이 문제의 함정은 '='를 처음 한 번만 나누는 것이에요. Python partition("=")이나 split("=", 1), Java split("=", 2), C# Split('=', 2)는 처음 '='에서만 자르고 나머지를 값에 남겨요. JS·TS의 split("=", 2)는 이름이 같아도 뜻이 달라요. 앞의 두 조각만 남기고 나머지를 버려서 "b=c=d"가 ["b", "c"]가 되니, indexOf("=")와 slice로 잘라요. 크레이콘도 자리찾기("=")와 부분문자열로 잘라요. Java split("=")처럼 한도 없이 자르면 "k=="가 ["k"]가 되어 값이 통째로 없어져요. 같은 이름이 두 번 나오면 값을 모두 보여 줘야 하니, 사전에 값 하나가 아니라 값 목록을 담아요.
Pythonmain.py · 18 줄
line = input()q = int(input())values = {} # 이름 → 값 목록(나온 차례대로)count = 0for piece in line.split("&"): if piece == "": continue # &&·맨 앞·맨 뒤의 &가 만든 빈 조각은 버린다 count += 1 # 처음 나오는 '='에서만 한 번 나눈다(값 안의 '='는 그대로) name, _, value = piece.partition("=") values.setdefault(name, []).append(value)print(count)for _ in range(q): name = input().strip() if name in values: print("".join(f"[{v}]" for v in values[name])) else: print("-")
JavaScriptmain.js · 20 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const q = Number(lines[1]);const values = new Map(); // 이름 → 값 배열(나온 차례대로)let count = 0;for (const piece of lines[0].trim().split("&")) { if (piece === "") continue; // 빈 조각은 버린다 count++; // 처음 나오는 '='에서만 자른다. split("=")은 값 안의 '='까지 자른다 const at = piece.indexOf("="); const name = at < 0 ? piece : piece.slice(0, at); const value = at < 0 ? "" : piece.slice(at + 1); if (!values.has(name)) values.set(name, []); values.get(name).push(value);}const out = [String(count)];for (let i = 0; i < q; i++) { const vs = values.get(lines[2 + i].trim()); out.push(vs ? vs.map((v) => `[${v}]`).join("") : "-");}console.log(out.join("\n"));
TypeScriptmain.ts · 22 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const q: number = Number(lines[1]);const values = new Map<string, string[]>(); // 이름 → 값 배열(나온 차례대로)let count = 0;for (const piece of lines[0].trim().split("&")) { if (piece === "") continue; // 빈 조각은 버린다 count++; // 처음 나오는 '='에서만 자른다. split("=")은 값 안의 '='까지 자른다 const at: number = piece.indexOf("="); const name: string = at < 0 ? piece : piece.slice(0, at); const value: string = at < 0 ? "" : piece.slice(at + 1); const list: string[] = values.get(name) ?? []; list.push(value); values.set(name, list);}const out: string[] = [String(count)];for (let i = 0; i < q; i++) { const vs: string[] | undefined = values.get(lines[2 + i].trim()); out.push(vs ? vs.map((v) => `[${v}]`).join("") : "-");}console.log(out.join("\n"));
JavaMain.java · 37 줄
import java.io.BufferedReader;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;public class Main { public static void main(String[] args) throws Exception { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String line = in.readLine().trim(); int q = Integer.parseInt(in.readLine().trim()); Map<String, List<String>> values = new HashMap<>(); // 이름 → 값 목록(나온 차례대로) int count = 0; // Java의 split은 맨 뒤의 빈 조각을 버리지만 맨 앞·가운데의 빈 조각은 남긴다 for (String piece : line.split("&")) { if (piece.isEmpty()) continue; count++; // 한도 2: 처음 '='에서 한 번만 자르고, 뒤의 빈 문자열도 남긴다 String[] kv = piece.split("=", 2); String value = kv.length > 1 ? kv[1] : ""; values.computeIfAbsent(kv[0], k -> new ArrayList<>()).add(value); } StringBuilder out = new StringBuilder(); out.append(count).append('\n'); for (int i = 0; i < q; i++) { List<String> vs = values.get(in.readLine().trim()); if (vs == null) { out.append("-\n"); continue; } for (String v : vs) out.append('[').append(v).append(']'); out.append('\n'); } System.out.print(out); }}
C#Main.cs · 43 줄
using System;using System.Collections.Generic;using System.Text;class Program{ static void Main() { string line = Console.ReadLine().Trim(); int q = int.Parse(Console.ReadLine()); var values = new Dictionary<string, List<string>>(); // 이름 → 값 목록(나온 차례대로) int count = 0; // RemoveEmptyEntries가 빈 조각을 버린다 foreach (string piece in line.Split('&', StringSplitOptions.RemoveEmptyEntries)) { count++; // 한도 2: 처음 '='에서 한 번만 자른다 string[] kv = piece.Split('=', 2); string value = kv.Length > 1 ? kv[1] : ""; if (!values.TryGetValue(kv[0], out var list)) { list = new List<string>(); values[kv[0]] = list; } list.Add(value); } var sb = new StringBuilder(); sb.Append(count).Append('\n'); for (int i = 0; i < q; i++) { if (values.TryGetValue(Console.ReadLine().Trim(), out var vs)) { foreach (string v in vs) sb.Append('[').Append(v).Append(']'); sb.Append('\n'); } else { sb.Append("-\n"); } } Console.Write(sb); }}
C++main.cpp · 36 줄
#include <iostream>#include <map>#include <sstream>#include <string>#include <vector>int main() { std::string line, piece; std::getline(std::cin, line); if (!line.empty() && line.back() == '\r') line.pop_back(); std::map<std::string, std::vector<std::string>> values; // 이름 → 값 목록(나온 차례대로) int count = 0; std::stringstream ss(line); // getline에 구분 글자를 주면 빈 조각도 하나씩 돌려준다 while (std::getline(ss, piece, '&')) { if (piece.empty()) continue; count++; std::size_t at = piece.find('='); // 처음 '='만 if (at == std::string::npos) values[piece].push_back(""); else values[piece.substr(0, at)].push_back(piece.substr(at + 1)); } std::cout << count << '\n'; int q; std::cin >> q; std::string key; for (int i = 0; i < q; i++) { std::cin >> key; auto it = values.find(key); if (it == values.end()) { std::cout << "-\n"; continue; } for (const auto &v : it->second) std::cout << '[' << v << ']'; std::cout << '\n'; }}
Cmain.c · 39 줄
#include <stdio.h>#include <string.h>static char line[10005];static char *names[5001], *vals[5001];int main(void) { int q, count = 0; if (!fgets(line, sizeof line, stdin)) return 0; line[strcspn(line, "\r\n")] = '\0'; /* strtok은 이어진 &를 하나로 보고 빈 조각을 건너뛴다 — 이 문제에는 딱 맞다 */ for (char *piece = strtok(line, "&"); piece; piece = strtok(NULL, "&")) { /* '='는 strtok으로 자르면 "a==b"의 '='가 사라진다. 처음 '='만 strchr로 찾는다 */ char *eq = strchr(piece, '='); if (eq) { *eq = '\0'; vals[count] = eq + 1; } else { vals[count] = ""; } names[count] = piece; count++; } printf("%d\n", count); scanf("%d", &q); char key[16]; for (int i = 0; i < q; i++) { scanf("%15s", key); int found = 0; for (int j = 0; j < count; j++) { if (strcmp(names[j], key) == 0) { printf("[%s]", vals[j]); found = 1; } } puts(found ? "" : "-"); } return 0;}
Craykonmain.cray · 44 줄
line = 콘솔.줄읽기().공백제거();q = 콘솔.줄읽기().수로변환();values = 사전(); // 이름 → 값 목록(나온 차례대로)count = 0;각각 (piece 에서 line.나누기("&")){ 만약 (piece == "") { 건너뛰기; // 빈 조각은 버린다 } count += 1; // 처음 나오는 '='에서만 자른다 at = piece.자리찾기("="); name = piece; value = ""; 만약 (at >= 0) { name = piece.부분문자열(0, at); value = piece.부분문자열(at + 1); } 만약 (!values.있나(name)) { values[name] = []; } values[name].넣기(value);}콘솔.쓰기(count);반복 (i = 0; i < q; i++){ key = 콘솔.줄읽기().공백제거(); 만약 (values.있나(key)) { out = ""; 각각 (v 에서 values[key]) { out += "[" + v + "]"; } 콘솔.쓰기(out); } 아니면 { 콘솔.쓰기("-"); }}