def normalize(url): # 조각(#)을 먼저 떼야 한다: 조각 안의 ?는 질의가 아니다 h = url.find("#") rest, frag = (url, "") if h == -1 else (url[:h], url[h:]) q = rest.find("?") path, query = (rest, "") if q == -1 else (rest[:q], rest[q:]) segs = path.split("/") stack = [] for seg in segs: if seg == "" or seg == ".": continue if seg == "..": if stack: # 맨 위에서는 더 올라가지 않는다 stack.pop() else: stack.append(seg) clean = "/" + "/".join(stack) # 마지막 이름이 빈 이름·.·.. 이면 폴더를 가리키니 끝의 / 를 남긴다 if stack and segs[-1] in ("", ".", ".."): clean += "/" return clean + query + fragn = int(input())for _ in range(n): print(normalize(input()))
JavaScriptmain.js · 25 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);function normalize(url) { // 조각(#)을 먼저 떼야 한다: 조각 안의 ?는 질의가 아니다 const h = url.indexOf("#"); const rest = h === -1 ? url : url.slice(0, h); const frag = h === -1 ? "" : url.slice(h); const q = rest.indexOf("?"); const path = q === -1 ? rest : rest.slice(0, q); const query = q === -1 ? "" : rest.slice(q); const stack = []; for (const seg of path.split("/")) { if (seg === "" || seg === ".") continue; if (seg === "..") stack.pop(); // 빈 배열의 pop()은 오류 없이 undefined else stack.push(seg); } let clean = "/" + stack.join("/"); // 마지막 이름이 빈 이름·.·.. 이면 폴더를 가리키니 끝의 / 를 남긴다 const last = path.slice(path.lastIndexOf("/") + 1); if (stack.length > 0 && (last === "" || last === "." || last === "..")) clean += "/"; return clean + query + frag;}console.log(lines.slice(1, 1 + n).map(normalize).join("\n"));
TypeScriptmain.ts · 26 行
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const n: number = Number(lines[0]);function normalize(url: string): string { // 조각(#)을 먼저 떼야 한다: 조각 안의 ?는 질의가 아니다 const h: number = url.indexOf("#"); const rest: string = h === -1 ? url : url.slice(0, h); const frag: string = h === -1 ? "" : url.slice(h); const q: number = rest.indexOf("?"); const path: string = q === -1 ? rest : rest.slice(0, q); const query: string = q === -1 ? "" : rest.slice(q); const stack: string[] = []; for (const seg of path.split("/")) { if (seg === "" || seg === ".") continue; if (seg === "..") stack.pop(); // 빈 배열의 pop()은 오류 없이 undefined else stack.push(seg); } let clean: string = "/" + stack.join("/"); // 마지막 이름이 빈 이름·.·.. 이면 폴더를 가리키니 끝의 / 를 남긴다 const last: string = path.slice(path.lastIndexOf("/") + 1); if (stack.length > 0 && (last === "" || last === "." || last === "..")) clean += "/"; return clean + query + frag;}console.log(lines.slice(1, 1 + n).map(normalize).join("\n"));
JavaMain.java · 39 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.List;public class Main { static String normalize(String url) { // 조각(#)을 먼저 떼야 한다: 조각 안의 ?는 질의가 아니다 int h = url.indexOf('#'); String rest = h == -1 ? url : url.substring(0, h); String frag = h == -1 ? "" : url.substring(h); int q = rest.indexOf('?'); String path = q == -1 ? rest : rest.substring(0, q); String query = q == -1 ? "" : rest.substring(q); List<String> stack = new ArrayList<>(); for (String seg : path.split("/")) { if (seg.isEmpty() || seg.equals(".")) continue; if (seg.equals("..")) { if (!stack.isEmpty()) stack.remove(stack.size() - 1); } else { stack.add(seg); } } String clean = "/" + String.join("/", stack); // 마지막 이름이 빈 이름·.·.. 이면 폴더를 가리키니 끝의 / 를 남긴다 String last = path.substring(path.lastIndexOf('/') + 1); if (!stack.isEmpty() && (last.isEmpty() || last.equals(".") || last.equals(".."))) clean += "/"; return clean + query + frag; } public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); int n = Integer.parseInt(in.readLine().trim()); StringBuilder out = new StringBuilder(); for (int i = 0; i < n; i++) out.append(normalize(in.readLine())).append('\n'); System.out.print(out); }}
C#Main.cs · 37 行
using System;using System.Collections.Generic;class Program{ static string Normalize(string url) { // 조각(#)을 먼저 떼야 한다: 조각 안의 ?는 질의가 아니다 int h = url.IndexOf('#'); string rest = h == -1 ? url : url.Substring(0, h); string frag = h == -1 ? "" : url.Substring(h); int q = rest.IndexOf('?'); string path = q == -1 ? rest : rest.Substring(0, q); string query = q == -1 ? "" : rest.Substring(q); var stack = new List<string>(); foreach (string seg in path.Split('/', StringSplitOptions.RemoveEmptyEntries)) { if (seg == ".") continue; if (seg == "..") { if (stack.Count > 0) stack.RemoveAt(stack.Count - 1); } else stack.Add(seg); } string clean = "/" + string.Join("/", stack); // 마지막 이름이 빈 이름·.·.. 이면 폴더를 가리키니 끝의 / 를 남긴다 string last = path.Substring(path.LastIndexOf('/') + 1); if (stack.Count > 0 && (last == "" || last == "." || last == "..")) clean += "/"; return clean + query + frag; } static void Main() { int n = int.Parse(Console.ReadLine()); for (int i = 0; i < n; i++) Console.WriteLine(Normalize(Console.ReadLine())); }}
C++main.cpp · 41 行
#include <iostream>#include <sstream>#include <string>#include <vector>std::string normalize(const std::string& url) { // 조각(#)을 먼저 떼야 한다: 조각 안의 ?는 질의가 아니다 size_t h = url.find('#'); std::string rest = url.substr(0, h); // h가 npos면 끝까지 std::string frag = h == std::string::npos ? "" : url.substr(h); size_t q = rest.find('?'); std::string path = rest.substr(0, q); std::string query = q == std::string::npos ? "" : rest.substr(q); std::vector<std::string> stack; std::stringstream ss(path); std::string seg; while (std::getline(ss, seg, '/')) { if (seg.empty() || seg == ".") continue; if (seg == "..") { if (!stack.empty()) stack.pop_back(); // 빈 vector의 pop_back은 정의되지 않은 동작 } else { stack.push_back(seg); } } std::string out = "/"; for (size_t k = 0; k < stack.size(); k++) { if (k > 0) out += '/'; out += stack[k]; } // 마지막 이름이 빈 이름·.·.. 이면 폴더를 가리키니 끝의 / 를 남긴다 std::string last = path.substr(path.rfind('/') + 1); if (!stack.empty() && (last.empty() || last == "." || last == "..")) out += '/'; return out + query + frag;}int main() { std::string line; std::getline(std::cin, line); int n = std::stoi(line); for (int i = 0; i < n && std::getline(std::cin, line); i++) std::cout << normalize(line) << '\n';}
Cmain.c · 42 行
#include <stdio.h>#include <string.h>int main(void) { int n; char url[256]; if (!fgets(url, sizeof url, stdin)) return 0; sscanf(url, "%d", &n); for (int i = 0; i < n; i++) { if (!fgets(url, sizeof url, stdin)) break; url[strcspn(url, "\n")] = '\0'; /* 조각(#)을 먼저 찾아야 한다: 조각 안의 ?는 질의가 아니다 */ char *h = strchr(url, '#'); char frag[256] = ""; if (h) { strcpy(frag, h); *h = '\0'; } char *q = strchr(url, '?'); char query[256] = ""; if (q) { strcpy(query, q); *q = '\0'; } /* 마지막 이름이 빈 이름·.·.. 이면 폴더를 가리킨다(strtok이 url을 바꾸기 전에 본다) */ const char *last = strrchr(url, '/') + 1; int dirLike = strcmp(last, "") == 0 || strcmp(last, ".") == 0 || strcmp(last, "..") == 0; /* 이제 url에는 경로만 남았다. strtok은 빈 조각("//")을 저절로 건너뛴다 */ char *stack[128]; int top = 0; for (char *seg = strtok(url, "/"); seg; seg = strtok(NULL, "/")) { if (strcmp(seg, ".") == 0) continue; if (strcmp(seg, "..") == 0) { if (top > 0) top--; } else { stack[top++] = seg; } } char out[512] = "/"; for (int k = 0; k < top; k++) { if (k > 0) strcat(out, "/"); strcat(out, stack[k]); } if (top > 0 && dirLike) strcat(out, "/"); printf("%s%s%s\n", out, query, frag); } return 0;}