가게의 영수증 인쇄기는 서식 문자열 하나로 줄마다 금액을 찍는다.
첫 줄에 서식 T가 주어진다.
T 안에서 { 와 } 로 감싼 부분이 자리 표시이고, 나머지 글자는 그대로 쓴다.
둘째 줄에 줄 수 n, 다음 n줄에 정수가 자리 표시의 수만큼 빈칸 하나씩으로 나뉘어 주어진다.
줄마다 T의 자리 표시를 왼쪽부터 차례로 그 줄의 정수로 바꾼 문자열을 출력한다.
자리 표시 { } 안의 서식은 [맞춤][+][0][너비][,] 차례이고, 어느 부분이든 없을 수 있다. 모두 없으면 {}이다.
맞춤은 < (왼쪽), > (오른쪽), ^ (가운데) 가운데 하나다. 없으면 오른쪽 맞춤이다.
+ 가 있으면 0과 양수 앞에 + 를 붙인다. 음수 앞에는 늘 - 를 붙이고, + 가 없으면 0과 양수에는 부호를 붙이지 않는다.
, 가 있으면 숫자 부분을 끝에서부터 세 자리마다 쉼표로 나눈다(1234567 → 1,234,567, -123 → -123). 부호는 세 자리에 세지 않는다.
너비는 1 이상 30 이하의 수이고 0으로 시작하지 않는다.
부호, 숫자, 쉼표를 합친 글자 수가 너비보다 작으면 빈칸을 채워 너비에 맞춘다. 너비와 같거나 크면 자르지도 채우지도 않는다. 너비가 없어도 채우지 않는다.
왼쪽 맞춤은 오른쪽에, 오른쪽 맞춤은 왼쪽에 빈칸을 채운다.
가운데 맞춤은 채울 빈칸 수의 반(나머지는 버림)을 왼쪽에, 남은 빈칸을 오른쪽에 채운다.
너비 앞에 0이 있으면 빈칸 대신 0을 부호와 숫자 사이에 채운다(-42를 서식 {06}으로 → -00042).
0은 맞춤과 쉼표가 없고 너비가 있을 때만 나온다.
출력하는 수는 쉼표와 부호 말고는 숫자만으로 쓴다.
입력
T는 4 ~ 200글자이고, 자리 표시는 1 ~ 10개다. 자리 표시 밖의 글자는 { 와 } 가 아닌 ASCII 글자(코드 32~126)다. T의 첫 글자와 마지막 글자는 빈칸도, { 나 } 도 아니다. 서식은 위의 규칙대로만 주어진다. 1 ≤ n ≤ 100. 정수는 -10^15 이상 10^15 이하
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이
서식 출력 기능이 언어마다 할 수 있는 것이 달라요. 이 문제의 서식은 Python 서식 규칙(format spec)의 일부라서 Python은 format(v, ">+12,")나 f-문자열 f"{v:>+12,}"가 그대로 처리해요. C++20 std::format("{:^+8}", v)도 같은 규칙이지만 쉼표 ,가 없어요(L은 로캘을 따라요). C printf("%+08lld", v)는 -(왼쪽), +, 0, 너비는 있지만 가운데 맞춤과 쉼표가 없어요(' 깃발은 POSIX 확장이고 로캘을 따라요). Java String.format("%+,8d", v)는 -·+·0·,가 있지만 가운데 맞춤이 없고, 쉼표 모양은 로캘을 따라서 Locale.ROOT를 주는 게 안전해요. C#은 {0,8:N0}처럼 너비(음수면 왼쪽)와 N0(세 자리 묶음)이 있지만 가운데 맞춤이 없고 +는 사용자 지정 서식(+#;-#;+0)으로만 붙어요(CultureInfo.InvariantCulture로 쉼표를 고정해요). JS·TS는 padStart/padEnd, 크레이콘은 앞채우기/뒤채우기로 채우고 쉼표는 직접 넣어요. 그래서 서식을 한 부분씩 읽어, 부호와 숫자를 따로 만든 뒤 채우는 것이 모든 언어에 통하는 방법이에요. 함정 ① 0 채우기를 맨 앞에 하면 -42가 00-42가 돼요. 0은 부호 뒤에 채워요. ② 부호까지 세어 쉼표를 넣으면 -123이 -,123이 돼요. 쉼표는 절댓값의 숫자에만 넣어요. ③ 가운데 맞춤에서 남는 빈칸 하나는 오른쪽이에요. ④ +는 0에도 붙어요(+0). ⑤ 너비보다 긴 값은 자르지 않아요. ⑥ 값이 ±10^15까지라서 C·C++ long long, Java·C# long이 필요해요(int는 약 21억까지). ⑦ C에서 그대로 쓸 글자를 printf(lit)처럼 서식 자리에 넣으면 %가 서식으로 읽혀요. fputs나 printf("%s", lit)로 써요.
Pythonmain.py · 12 줄
import reimport syslines = sys.stdin.read().split("\n")template = lines[0]n = int(lines[1])# 홀수 칸이 자리 표시의 서식, 짝수 칸이 그대로 쓸 글자: "a{>5}b" → ["a", ">5", "b"]parts = re.split(r"\{([^}]*)\}", template)for row in lines[2:2 + n]: values = iter(map(int, row.split())) # 이 문제의 서식은 Python 서식 규칙(format spec)의 일부라서 format이 그대로 처리한다 print("".join(format(next(values), p) if i % 2 else p for i, p in enumerate(parts)))
JavaScriptmain.js · 39 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const template = lines[0];const n = Number(lines[1]);// 홀수 칸이 자리 표시의 서식, 짝수 칸이 그대로 쓸 글자const parts = template.split(/\{([^}]*)\}/);function format(v, spec) { let i = 0; let align = ""; if (i < spec.length && "<>^".includes(spec[i])) align = spec[i++]; let plus = false, zero = false; if (spec[i] === "+") { plus = true; i++; } if (spec[i] === "0") { zero = true; i++; } let width = 0; while (i < spec.length && spec[i] >= "0" && spec[i] <= "9") width = width * 10 + Number(spec[i++]); const comma = spec[i] === ","; let digits = String(Math.abs(v)); if (comma) digits = digits.replace(/\B(?=(\d{3})+$)/g, ","); // 끝에서부터 세 자리마다 const sign = v < 0 ? "-" : plus ? "+" : ""; const s = sign + digits; const gap = width - s.length; if (gap <= 0) return s; // 너비보다 길면 자르지 않는다 if (zero) return sign + "0".repeat(gap) + digits; // 0은 부호 뒤에 채운다 if (align === "<") return s.padEnd(width); if (align === "^") { const left = Math.floor(gap / 2); return " ".repeat(left) + s + " ".repeat(gap - left); } return s.padStart(width);}const out = [];for (const row of lines.slice(2, 2 + n)) { const values = row.trim().split(/\s+/).map(Number); let k = 0; out.push(parts.map((p, i) => (i % 2 === 1 ? format(values[k++], p) : p)).join(""));}console.log(out.join("\n"));
TypeScriptmain.ts · 41 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const template = lines[0];const n = Number(lines[1]);// 홀수 칸이 자리 표시의 서식, 짝수 칸이 그대로 쓸 글자const parts: string[] = template.split(/\{([^}]*)\}/);function format(v: number, spec: string): string { let i = 0; let align = ""; if (i < spec.length && "<>^".includes(spec[i])) align = spec[i++]; let plus = false, zero = false; if (spec[i] === "+") { plus = true; i++; } if (spec[i] === "0") { zero = true; i++; } let width = 0; while (i < spec.length && spec[i] >= "0" && spec[i] <= "9") width = width * 10 + Number(spec[i++]); const comma = spec[i] === ","; let digits = String(Math.abs(v)); if (comma) digits = digits.replace(/\B(?=(\d{3})+$)/g, ","); // 끝에서부터 세 자리마다 const sign = v < 0 ? "-" : plus ? "+" : ""; const s = sign + digits; const gap = width - s.length; if (gap <= 0) return s; // 너비보다 길면 자르지 않는다 if (zero) return sign + "0".repeat(gap) + digits; // 0은 부호 뒤에 채운다 if (align === "<") return s.padEnd(width); if (align === "^") { const left = Math.floor(gap / 2); return " ".repeat(left) + s + " ".repeat(gap - left); } return s.padStart(width);}const out: string[] = [];for (const row of lines.slice(2, 2 + n)) { const values = row.trim().split(/\s+/).map(Number); let k = 0; out.push(parts.map((p, i) => (i % 2 === 1 ? format(values[k++], p) : p)).join(""));}console.log(out.join("\n"));
JavaMain.java · 57 줄
import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.IOException;import java.util.ArrayList;import java.util.List;public class Main { static String format(long v, String spec) { int i = 0; char align = ' '; if (i < spec.length() && "<>^".indexOf(spec.charAt(i)) >= 0) align = spec.charAt(i++); boolean plus = false, zero = false; if (i < spec.length() && spec.charAt(i) == '+') { plus = true; i++; } if (i < spec.length() && spec.charAt(i) == '0') { zero = true; i++; } int width = 0; while (i < spec.length() && Character.isDigit(spec.charAt(i))) width = width * 10 + (spec.charAt(i++) - '0'); boolean comma = i < spec.length() && spec.charAt(i) == ','; // %,d는 세 자리마다 쉼표를 넣는다(Locale.ROOT로 쉼표를 고정). 부호는 따로 붙인다 String digits = String.format(java.util.Locale.ROOT, comma ? "%,d" : "%d", Math.abs(v)); String sign = v < 0 ? "-" : plus ? "+" : ""; String s = sign + digits; int gap = width - s.length(); if (gap <= 0) return s; // 너비보다 길면 자르지 않는다 if (zero) return sign + "0".repeat(gap) + digits; // 0은 부호 뒤에 채운다 if (align == '<') return s + " ".repeat(gap); if (align == '^') return " ".repeat(gap / 2) + s + " ".repeat(gap - gap / 2); return " ".repeat(gap) + s; } public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String template = in.readLine(); // 자리 표시와 그 사이 글자로 나눈다 List<String> lits = new ArrayList<>(), specs = new ArrayList<>(); int from = 0; while (true) { int open = template.indexOf('{', from); if (open < 0) break; int close = template.indexOf('}', open); lits.add(template.substring(from, open)); specs.add(template.substring(open + 1, close)); from = close + 1; } lits.add(template.substring(from)); int n = Integer.parseInt(in.readLine().trim()); StringBuilder out = new StringBuilder(); for (int r = 0; r < n; r++) { String[] vs = in.readLine().trim().split("\\s+"); for (int k = 0; k < specs.size(); k++) { out.append(lits.get(k)).append(format(Long.parseLong(vs[k]), specs.get(k))); } out.append(lits.get(specs.size())).append('\n'); } System.out.print(out); }}
C#Main.cs · 60 줄
using System;using System.Collections.Generic;using System.Globalization;using System.Text;class Program{ static string Format(long v, string spec) { int i = 0; char align = ' '; if (i < spec.Length && "<>^".IndexOf(spec[i]) >= 0) align = spec[i++]; bool plus = false, zero = false; if (i < spec.Length && spec[i] == '+') { plus = true; i++; } if (i < spec.Length && spec[i] == '0') { zero = true; i++; } int width = 0; while (i < spec.Length && char.IsDigit(spec[i])) width = width * 10 + (spec[i++] - '0'); bool comma = i < spec.Length && spec[i] == ','; // "N0"은 세 자리마다 묶는다(InvariantCulture라야 쉼표). 부호는 따로 붙인다 long a = Math.Abs(v); string digits = comma ? a.ToString("N0", CultureInfo.InvariantCulture) : a.ToString(CultureInfo.InvariantCulture); string sign = v < 0 ? "-" : plus ? "+" : ""; string s = sign + digits; int gap = width - s.Length; if (gap <= 0) return s; // 너비보다 길면 자르지 않는다 if (zero) return sign + new string('0', gap) + digits; // 0은 부호 뒤에 채운다 if (align == '<') return s.PadRight(width); if (align == '^') return new string(' ', gap / 2) + s + new string(' ', gap - gap / 2); return s.PadLeft(width); } static void Main() { string template = Console.ReadLine(); var lits = new List<string>(); var specs = new List<string>(); int from = 0; while (true) { int open = template.IndexOf('{', from); if (open < 0) break; int close = template.IndexOf('}', open); lits.Add(template.Substring(from, open - from)); specs.Add(template.Substring(open + 1, close - open - 1)); from = close + 1; } lits.Add(template.Substring(from)); int n = int.Parse(Console.ReadLine().Trim()); var sb = new StringBuilder(); for (int r = 0; r < n; r++) { string[] vs = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries); for (int k = 0; k < specs.Count; k++) sb.Append(lits[k]).Append(Format(long.Parse(vs[k]), specs[k])); sb.Append(lits[specs.Count]).Append('\n'); } Console.Write(sb); }}
C++main.cpp · 57 줄
#include <cstdlib>#include <iostream>#include <string>#include <vector>// 서식 spec으로 v를 문자열로 만든다std::string format(long long v, const std::string &spec) { size_t i = 0; char align = ' '; if (i < spec.size() && std::string("<>^").find(spec[i]) != std::string::npos) align = spec[i++]; bool plus = false, zero = false; if (i < spec.size() && spec[i] == '+') { plus = true; i++; } if (i < spec.size() && spec[i] == '0') { zero = true; i++; } int width = 0; while (i < spec.size() && std::isdigit(static_cast<unsigned char>(spec[i]))) width = width * 10 + (spec[i++] - '0'); bool comma = i < spec.size() && spec[i] == ','; std::string raw = std::to_string(std::llabs(v)), digits; for (size_t j = 0; j < raw.size(); j++) { if (comma && j > 0 && (raw.size() - j) % 3 == 0) digits += ','; // 끝에서 세 자리마다 digits += raw[j]; } std::string sign = v < 0 ? "-" : plus ? "+" : ""; std::string s = sign + digits; int gap = width - static_cast<int>(s.size()); if (gap <= 0) return s; // 너비보다 길면 자르지 않는다 if (zero) return sign + std::string(gap, '0') + digits; // 0은 부호 뒤에 채운다 if (align == '<') return s + std::string(gap, ' '); if (align == '^') return std::string(gap / 2, ' ') + s + std::string(gap - gap / 2, ' '); return std::string(gap, ' ') + s;}int main() { std::string tmpl; std::getline(std::cin, tmpl); std::vector<std::string> lits, specs; size_t from = 0; for (size_t open; (open = tmpl.find('{', from)) != std::string::npos;) { size_t close = tmpl.find('}', open); lits.push_back(tmpl.substr(from, open - from)); specs.push_back(tmpl.substr(open + 1, close - open - 1)); from = close + 1; } lits.push_back(tmpl.substr(from)); int n; std::cin >> n; std::string out; for (int r = 0; r < n; r++) { for (size_t k = 0; k < specs.size(); k++) { long long v; std::cin >> v; out += lits[k] + format(v, specs[k]); } out += lits.back() + '\n'; } std::cout << out;}
Cmain.c · 61 줄
#include <stdio.h>#include <string.h>static char tmpl[256];static const char ZEROS[] = "000000000000000000000000000000"; /* 너비는 30 이하 *//* 서식 spec으로 v를 out에 쓴다 */static void format(long long v, const char *spec, char *out) { int i = 0, width = 0, plus = 0, zero = 0, comma = 0; char align = ' '; if (spec[i] && strchr("<>^", spec[i])) align = spec[i++]; if (spec[i] == '+') { plus = 1; i++; } if (spec[i] == '0') { zero = 1; i++; } while (spec[i] >= '0' && spec[i] <= '9') width = width * 10 + (spec[i++] - '0'); if (spec[i] == ',') comma = 1; /* 절댓값의 숫자들. v는 ±10^15 이하라 -v가 넘치지 않는다 */ char raw[24], digits[32]; snprintf(raw, sizeof raw, "%lld", v < 0 ? -v : v); int len = (int)strlen(raw), d = 0; for (int j = 0; j < len; j++) { if (comma && j > 0 && (len - j) % 3 == 0) digits[d++] = ','; /* 끝에서 세 자리마다 */ digits[d++] = raw[j]; } digits[d] = '\0'; const char *sign = v < 0 ? "-" : plus ? "+" : ""; int slen = (int)strlen(sign) + d; int gap = width - slen; if (gap < 0) gap = 0; /* 너비보다 길면 자르지 않는다 */ if (zero) sprintf(out, "%s%.*s%s", sign, gap, ZEROS, digits); /* 0은 부호 뒤에 채운다 */ else if (align == '<') sprintf(out, "%s%s%*s", sign, digits, gap, ""); else if (align == '^') sprintf(out, "%*s%s%s%*s", gap / 2, "", sign, digits, gap - gap / 2, ""); else sprintf(out, "%*s%s%s", gap, "", sign, digits);}int main(void) { fgets(tmpl, sizeof tmpl, stdin); tmpl[strcspn(tmpl, "\r\n")] = '\0'; int n; scanf("%d", &n); for (int r = 0; r < n; r++) { for (char *p = tmpl; *p;) { if (*p == '{') { char spec[16], cell[64]; char *close = strchr(p, '}'); int sl = (int)(close - p - 1); memcpy(spec, p + 1, sl); spec[sl] = '\0'; long long v; scanf("%lld", &v); format(v, spec, cell); fputs(cell, stdout); p = close + 1; } else { putchar(*p++); /* 그대로 쓸 글자는 printf의 서식으로 쓰지 않는다(% 때문에) */ } } putchar('\n'); } return 0;}
Craykonmain.cray · 95 줄
// 서식 spec으로 v를 문자열로 만든다서식(v, spec){ i = 0; align = ""; 만약 (i < spec.길이 && "<>^".있나(spec[i])) { align = spec[i]; i++; } plus = 거짓; zero = 거짓; 만약 (i < spec.길이 && spec[i] == "+") { plus = 참; i++; } 만약 (i < spec.길이 && spec[i] == "0") { zero = 참; i++; } width = 0; 동안 (i < spec.길이 && "0123456789".있나(spec[i])) { width = width * 10 + spec[i].수로변환(); i++; } comma = i < spec.길이 && spec[i] == ","; raw = "" + 수학.절댓값(v); digits = ""; 반복 (j = 0; j < raw.길이; j++) { 만약 (comma && j > 0 && (raw.길이 - j) % 3 == 0) { digits = digits + ","; // 끝에서 세 자리마다 } digits = digits + raw[j]; } sign = ""; 만약 (v < 0) { sign = "-"; } 아니면 만약 (plus) { sign = "+"; } s = sign + digits; 만약 (s.길이 >= width) { 돌려주기 s; // 너비보다 길면 자르지 않는다 } 만약 (zero) { 돌려주기 sign + digits.앞채우기(width - sign.길이, "0"); // 0은 부호 뒤에 채운다 } 만약 (align == "<") { 돌려주기 s.뒤채우기(width); } 만약 (align == "^") { left = 수학.몫(width - s.길이, 2); 돌려주기 (" ".되풀이(left) + s).뒤채우기(width); } 돌려주기 s.앞채우기(width);}tmpl = 콘솔.줄읽기();lits = [];specs = [];rest = tmpl;open = rest.자리찾기("{");동안 (open >= 0){ close = rest.자리찾기("}"); lits.넣기(rest.부분문자열(0, open)); specs.넣기(rest.부분문자열(open + 1, close - open - 1)); rest = rest.부분문자열(close + 1); open = rest.자리찾기("{");}lits.넣기(rest);n = 콘솔.줄읽기().수로변환();반복 (r = 0; r < n; r++){ vs = 콘솔.수들읽기(); line = ""; 반복 (k = 0; k < specs.개수; k++) { line = line + lits[k] + 서식(vs[k], specs[k]); } 콘솔.쓰기(line + lits[specs.개수]);}