{ }codelper
문자열 나누기사전 찾기P0236

주소 뒤에 붙은 설정 읽기

웹 주소의 물음표 뒤에 붙는 설정 문자열 한 줄이 주어진다. 설정 문자열은 영어 소문자, 숫자, '=', '&'로만 되어 있다. 먼저 설정 문자열을 '&'로 나눈다. 나눈 조각 가운데 빈 조각은 버린다.
빈 조각은 &가 이어지거나 맨 앞이나 맨 뒤에 &가 있을 때 생긴다. 남은 조각마다, 처음 나오는 '='의 앞이 이름이고 뒤가 값이다. 값에는 '='가 또 들어 있을 수 있고, 값이 빈 문자열일 수도 있다. '='가 없는 조각은 조각 전체가 이름이고 값은 빈 문자열이다. 어떤 조각도 '='로 시작하지 않는다. 둘째 줄에 질문 수 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
입력(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);    }    아니면    {        콘솔.쓰기("-");    }}