파일 목록 화면은 이름을 w글자까지만 보여 줄 수 있어서, 긴 이름은 가운데를 "..."으로 줄인다.
길이가 w 이하인 이름은 그대로 출력한다.
길이가 w보다 긴 이름은 다음과 같이 정확히 w글자로 줄인다.
이름에 '.'이 있으면 마지막 '.'부터 끝까지가 확장자이고, '.'이 없으면 확장자는 없다.
확장자를 뺀 앞부분에서 남길 글자 수 r은 w에서 3과 확장자의 길이를 뺀 값이다.
r이 1 이상이면 앞부분의 처음 ⌈r/2⌉글자, "...", 앞부분의 마지막 ⌊r/2⌋글자, 확장자를 차례로 이어 붙인다.
r이 1보다 작으면 확장자를 따로 두지 않고, 이름 전체를 앞부분으로 보고 r을 w − 3으로 하여 같은 방법으로 줄인다.
이름을 입력에 나온 차례대로 한 줄에 하나씩 출력하라.
마지막 줄에는 줄인 이름의 수를 출력하라.
입력
첫 줄에 w와 이름의 수 n(4 ≤ w ≤ 100, 1 ≤ n ≤ 1,000). 이어서 n줄에 이름이 하나씩 주어진다. 이름은 1~200글자이고 출력 가능한 ASCII 글자로 이루어지며, 가운데에 빈칸이 있을 수 있지만 빈칸으로 시작하거나 끝나지 않는다
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이
자르는 도구의 약속이 언어마다 달라요. Python s[a:b], JS·TS slice(a, b), Java substring(a, b)는 시작과 끝 위치를 받고, C# Substring(a, 길이), C++ substr(a, 길이), 크레이콘 부분문자열(a, 길이)는 시작과 길이를 받아요. C는 printf("%.*s", 길이, 시작)으로 조각을 바로 찍어요. 마지막 '.'은 Python rfind, JS·TS·Java lastIndexOf, C# LastIndexOf, C strrchr, C++ rfind로 찾고, 크레이콘은 끝에서부터 한 글자씩 보며 찾아요. 함정 하나: 뒤 조각을 음수 위치로 자르면 남길 글자가 0개일 때 틀려요. Python stem[-0:]과 JS slice(-0)은 빈 문자열이 아니라 문자열 전체예요. 예시의 interface-font.woff2는 r이 1이라 뒤 조각이 0글자인데, 이렇게 자르면 i...interface-font.woff2가 나와요. stem[len(stem) - tail:]처럼 앞에서 센 위치로 잘라요. 함정 둘: '.'이 없으면 Python rfind와 JS·TS·Java lastIndexOf, C# LastIndexOf는 -1을, C++ rfind는 npos를, C strrchr는 NULL을 돌려줘요. 확인하지 않고 Python name[-1:]로 자르면 마지막 한 글자가 확장자가 돼서 예시의 Makefile_for_release가 Mak...ease가 돼요. 함정 셋: 확장자는 마지막 '.'부터예요. Python find로 첫 '.'에서 자르면 예시의 archive.tar.gz가 ar...ar.gz가 아니라 arch....gz가 돼요. 함정 넷: r에서 확장자 길이를 빼지 않으면 w글자를 넘어요. 예시 둘째 이름이 14글자인 quar...nal.txt가 돼요. 함정 다섯: r이 1보다 작을 때의 규칙을 빠뜨리면 예시의 a.tar.gz.backup이 a.ta...kup이 아니라 ....backup이 돼요. 함정 여섯: 앞 조각이 올림이고 뒤 조각이 내림이에요. 바꾸면 예시 둘째 이름이 qu...l.txt가 아니라 q...al.txt가 돼요. 함정 일곱: 길이가 정확히 w인 이름은 그대로예요. <로 비교하면 예시의 report.txt가 re...t.txt가 돼요. 함정 여덟: 시작·끝과 시작·길이를 섞으면 안 돼요. Java substring(len - tail, tail)처럼 길이를 넘기면 예시 둘째 이름에서 시작이 끝보다 커서 StringIndexOutOfBoundsException으로 멈추고, 크레이콘 부분문자열(len - tail, len)처럼 끝 위치를 넘기면 자르는 자리가 문자열 밖이라는 오류로 멈춰요. 함정 아홉: 이름에 빈칸이 있을 수 있어서 한 줄을 통째로 읽어요. C++에서 std::cin >> w >> n 바로 다음에 getline을 부르면 첫 줄에 남은 줄 바꿈만 읽어서, 빈 줄이 먼저 나오고 마지막 이름을 놓쳐요. 첫 줄도 getline으로 읽어요.
Pythonmain.py · 24 줄
import syslines = sys.stdin.read().split("\n")w, n = map(int, lines[0].split())out = []count = 0for name in lines[1:n + 1]: if len(name) <= w: # 길이가 w 이하면 그대로 out.append(name) continue dot = name.rfind(".") # 마지막 '.', 없으면 -1 ext = name[dot:] if dot >= 0 else "" r = w - 3 - len(ext) # 확장자 앞부분에서 남길 글자 수 if r < 1: # 자리가 없으면 확장자를 따로 두지 않는다 ext = "" r = w - 3 stem = name[:len(name) - len(ext)] head = (r + 1) // 2 # 앞 조각은 올림 tail = r // 2 # 뒤 조각은 내림 # stem[-tail:]은 tail이 0일 때 전체가 되므로 앞에서 센 위치로 자른다 out.append(stem[:head] + "..." + stem[len(stem) - tail:] + ext) count += 1out.append(str(count))print("\n".join(out))
JavaScriptmain.js · 26 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const [w, n] = lines[0].split(" ").map(Number);const out = [];let count = 0;for (let i = 1; i <= n; i++) { const name = lines[i]; if (name.length <= w) { // 길이가 w 이하면 그대로 out.push(name); continue; } const dot = name.lastIndexOf("."); // 마지막 '.', 없으면 -1 let ext = dot >= 0 ? name.slice(dot) : ""; let r = w - 3 - ext.length; // 확장자 앞부분에서 남길 글자 수 if (r < 1) { // 자리가 없으면 확장자를 따로 두지 않는다 ext = ""; r = w - 3; } const stem = name.slice(0, name.length - ext.length); const head = Math.ceil(r / 2); // 앞 조각은 올림 const tail = Math.floor(r / 2); // 뒤 조각은 내림 // slice(-tail)은 tail이 0일 때 전체가 되므로 앞에서 센 위치로 자른다 out.push(stem.slice(0, head) + "..." + stem.slice(stem.length - tail) + ext); count++;}out.push(String(count));console.log(out.join("\n"));
TypeScriptmain.ts · 28 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const [w, n] = lines[0].split(" ").map(Number);const out: string[] = [];let count = 0;for (let i = 1; i <= n; i++) { const name = lines[i]; if (name.length <= w) { // 길이가 w 이하면 그대로 out.push(name); continue; } const dot = name.lastIndexOf("."); // 마지막 '.', 없으면 -1 let ext = dot >= 0 ? name.slice(dot) : ""; let r = w - 3 - ext.length; // 확장자 앞부분에서 남길 글자 수 if (r < 1) { // 자리가 없으면 확장자를 따로 두지 않는다 ext = ""; r = w - 3; } const stem = name.slice(0, name.length - ext.length); const head = Math.ceil(r / 2); // 앞 조각은 올림 const tail = Math.floor(r / 2); // 뒤 조각은 내림 // slice(-tail)은 tail이 0일 때 전체가 되므로 앞에서 센 위치로 자른다 out.push(stem.slice(0, head) + "..." + stem.slice(stem.length - tail) + ext); count++;}out.push(String(count));console.log(out.join("\n"));
JavaMain.java · 37 줄
import java.io.BufferedReader;import java.io.InputStreamReader;import java.util.StringTokenizer;public class Main { public static void main(String[] args) throws Exception { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer st = new StringTokenizer(in.readLine()); int w = Integer.parseInt(st.nextToken()); int n = Integer.parseInt(st.nextToken()); StringBuilder out = new StringBuilder(); int count = 0; for (int i = 0; i < n; i++) { String name = in.readLine(); if (name.length() <= w) { // 길이가 w 이하면 그대로 out.append(name).append('\n'); continue; } int dot = name.lastIndexOf('.'); // 마지막 '.', 없으면 -1 String ext = dot >= 0 ? name.substring(dot) : ""; int r = w - 3 - ext.length(); // 확장자 앞부분에서 남길 글자 수 if (r < 1) { // 자리가 없으면 확장자를 따로 두지 않는다 ext = ""; r = w - 3; } String stem = name.substring(0, name.length() - ext.length()); int head = (r + 1) / 2; // 앞 조각은 올림 int tail = r / 2; // 뒤 조각은 내림 // substring(시작, 끝)과 substring(시작) out.append(stem.substring(0, head)).append("...") .append(stem.substring(stem.length() - tail)).append(ext).append('\n'); count++; } out.append(count).append('\n'); System.out.print(out); }}
C#Main.cs · 40 줄
using System;using System.Text;class Program{ static void Main() { string[] first = Console.ReadLine()!.Split(' '); int w = int.Parse(first[0]); int n = int.Parse(first[1]); var sb = new StringBuilder(); int count = 0; for (int i = 0; i < n; i++) { string name = Console.ReadLine()!; if (name.Length <= w) // 길이가 w 이하면 그대로 { sb.Append(name).Append('\n'); continue; } int dot = name.LastIndexOf('.'); // 마지막 '.', 없으면 -1 string ext = dot >= 0 ? name.Substring(dot) : ""; int r = w - 3 - ext.Length; // 확장자 앞부분에서 남길 글자 수 if (r < 1) // 자리가 없으면 확장자를 따로 두지 않는다 { ext = ""; r = w - 3; } string stem = name.Substring(0, name.Length - ext.Length); int head = (r + 1) / 2; // 앞 조각은 올림 int tail = r / 2; // 뒤 조각은 내림 // Substring(시작, 길이)와 Substring(시작) sb.Append(stem.Substring(0, head)).Append("...") .Append(stem.Substring(stem.Length - tail)).Append(ext).Append('\n'); count++; } sb.Append(count).Append('\n'); Console.Write(sb); }}
C++main.cpp · 38 줄
#include <iostream>#include <sstream>#include <string>int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::string line; std::getline(std::cin, line); // 첫 줄도 getline으로 읽어 줄 바꿈을 남기지 않는다 std::istringstream first(line); int w, n; first >> w >> n; int count = 0; for (int i = 0; i < n; i++) { std::string name; std::getline(std::cin, name); int len = (int)name.size(); if (len <= w) { // 길이가 w 이하면 그대로 std::cout << name << '\n'; continue; } std::size_t dot = name.rfind('.'); // 마지막 '.', 없으면 npos std::string ext = dot != std::string::npos ? name.substr(dot) : ""; int r = w - 3 - (int)ext.size(); // 확장자 앞부분에서 남길 글자 수 if (r < 1) { // 자리가 없으면 확장자를 따로 두지 않는다 ext = ""; r = w - 3; } std::string stem = name.substr(0, name.size() - ext.size()); int head = (r + 1) / 2; // 앞 조각은 올림 int tail = r / 2; // 뒤 조각은 내림 // substr(시작, 길이)와 substr(시작) std::cout << stem.substr(0, head) << "..." << stem.substr(stem.size() - tail) << ext << '\n'; count++; } std::cout << count << '\n'; return 0;}
Cmain.c · 32 줄
#include <stdio.h>#include <string.h>int main(void) { static char name[256]; int w, n, count = 0; if (!fgets(name, sizeof name, stdin) || sscanf(name, "%d %d", &w, &n) != 2) return 0; for (int i = 0; i < n; i++) { if (!fgets(name, sizeof name, stdin)) break; int len = (int)strcspn(name, "\r\n"); name[len] = '\0'; if (len <= w) { /* 길이가 w 이하면 그대로 */ puts(name); continue; } const char *dot = strrchr(name, '.'); /* 마지막 '.', 없으면 NULL */ int ext = dot ? (int)(name + len - dot) : 0; int r = w - 3 - ext; /* 확장자 앞부분에서 남길 글자 수 */ if (r < 1) { /* 자리가 없으면 확장자를 따로 두지 않는다 */ ext = 0; r = w - 3; } int stem = len - ext; int head = (r + 1) / 2; /* 앞 조각은 올림 */ int tail = r / 2; /* 뒤 조각은 내림 */ /* %.*s는 길이만큼만 찍는다. 뒤 조각과 확장자는 이어져 있으니 끝까지 찍는다 */ printf("%.*s...%s\n", head, name, name + stem - tail); count++; } printf("%d\n", count); return 0;}
Craykonmain.cray · 36 줄
first = 콘솔.수들읽기();w = first[0];n = first[1];count = 0;반복 (i = 0; i < n; i++){ name = 콘솔.줄읽기(); 만약 (name.길이 <= w) { 콘솔.쓰기(name); 건너뛰기; } dot = name.길이 - 1; // 끝에서부터 마지막 '.'을 찾는다. 없으면 -1 동안 (dot >= 0 && name[dot] != ".") { dot -= 1; } ext = ""; 만약 (dot >= 0) { ext = name.부분문자열(dot); } r = w - 3 - ext.길이; // 확장자 앞부분에서 남길 글자 수 만약 (r < 1) { ext = ""; r = w - 3; } stem = name.부분문자열(0, name.길이 - ext.길이); tail = 수학.몫(r, 2); // 뒤 조각은 내림 head = r - tail; // 앞 조각은 올림 // 부분문자열(시작, 길이)와 부분문자열(시작) 콘솔.쓰기(stem.부분문자열(0, head) + "..." + stem.부분문자열(stem.길이 - tail) + ext); count += 1;}콘솔.쓰기(count);