{ }codelper
formatted outputpaddingP0241

Receipt printer format strings

A shop's receipt printer prints amounts on each line using one format string. The first line gives the format T. Inside T, a part wrapped in { and } is a placeholder, and every other character is written as it is. The second line gives the number of lines n, and each of the next n lines gives as many integers as there are placeholders, separated by single spaces. For each line, print T with its placeholders replaced, from left to right, by that line's integers. The format inside a placeholder { } is, in order, [align][+][0][width][,], and any part may be missing.
If all are missing it is {}. The align is one of < (left), > (right) and ^ (center).
If it is missing, the value is right-aligned. If + is present, put + before zero and positive numbers.
A negative number always gets -, and without + zero and positive numbers get no sign. If , is present, split the digit part with a comma every three digits from the end (1234567 → 1,234,567, -123 → -123).
The sign does not count toward the three digits. The width is a number from 1 to 30 and does not start with 0. If the total length of sign, digits and commas is less than the width, pad with spaces up to the width.
If it is equal or longer, neither cut nor pad.
Without a width, do not pad. Left alignment pads on the right, and right alignment pads on the left. Center alignment puts half of the padding (rounded down) on the left and the rest on the right. If a 0 comes before the width, pad with 0 between the sign and the digits instead of spaces (-42 with the format {06} → -00042). The 0 appears only when there is no align and no comma and there is a width. Apart from commas and the sign, numbers are printed as plain digits.

Input
T has 4–200 characters and 1–10 placeholders.
Characters outside placeholders are ASCII (codes 32–126) other than { and }.
The first and last characters of T are neither a space nor { or }.
Formats are always given following the rules above.
1 ≤ n ≤ 100.
The integers are from -10^15 to 10^15
Output
n lines
Example 1 · stdin
[{<6}|{>6}|{^6}|{06}|{+}|{,}]
2
42 42 42 -42 0 -1234567
-7 123456 12345 5 9 123
stdout
[42    |    42|  42  |-00042|+0|-1,234,567]
[-7    |123456|12345 |000005|+9|123]
Example 2 · stdin
Total:{>+12,}won
3
1500000
-25000
0
stdout
Total:  +1,500,000won
Total:     -25,000won
Total:          +0won
main.py
Input (stdin)

When you run, these lines are fed to input()/stdin in order (the program doesn't stop to ask).

$ Ready

Open this on a computer to write and run code. On mobile you can read the problem and the solutions.

In other languagesShow solutions by language · 8 languages

Formatted output can do different things in each language.
The format in this problem is a subset of Python's format spec, so in Python format(v, ">+12,") or the f-string f"{v:>+12,}" does it all.
C++20 std::format("{:^+8}", v) follows the same rules but has no comma , (L follows the locale).
C printf("%+08lld", v) has - (left), +, 0 and width, but no centering and no commas (the ' flag is a POSIX extension that follows the locale).
Java String.format("%+,8d", v) has -, +, 0 and , but no centering, and the comma style follows the locale, so passing Locale.ROOT is safer.
C# has width (negative means left) and N0 (groups of three) as in {0,8:N0}, but no centering, and + only comes from a custom format such as +#;-#;+0 (fix the comma with CultureInfo.InvariantCulture).
JS/TS pad with padStart/padEnd, Craykon with PadLeft/PadRight, and you insert commas yourself.
So the method that works in every language is to read the format part by part, build the sign and the digits separately, and then pad.
Trap ① zero-padding at the very front turns -42 into 00-42.
Pad zeros after the sign.
② Counting the sign when inserting commas turns -123 into -,123.
Put commas only into the digits of the absolute value.
③ When centering, the one leftover space goes on the right.
④ + also applies to zero (+0).
⑤ A value longer than the width is not cut.
⑥ Values go up to ±10^15, so C/C++ need long long and Java/C# need long (int only reaches about 2.1 billion).
⑦ In C, putting the literal text in the format position, as in printf(lit), makes % read as a format.
Use fputs or printf("%s", lit).

Pythonmain.py · 12 lines
import reimport sys lines = 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 lines
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 lines
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 lines
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 lines
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 lines
#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 lines
#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 lines
// 서식 spec으로 v를 문자열로 만든다서식(v, spec){    i = 0;    align = "";    if (i < spec.Length && "<>^".Contains(spec[i]))    {        align = spec[i];        i++;    }    plus = false;    zero = false;    if (i < spec.Length && spec[i] == "+")    {        plus = true;        i++;    }    if (i < spec.Length && spec[i] == "0")    {        zero = true;        i++;    }    width = 0;    while (i < spec.Length && "0123456789".Contains(spec[i]))    {        width = width * 10 + spec[i].ToNumber();        i++;    }    comma = i < spec.Length && spec[i] == ",";     raw = "" + Mathf.Abs(v);    digits = "";    for (j = 0; j < raw.Length; j++)    {        if (comma && j > 0 && (raw.Length - j) % 3 == 0)        {            digits = digits + ","; // 끝에서 세 자리마다        }        digits = digits + raw[j];    }    sign = "";    if (v < 0)    {        sign = "-";    }    else if (plus)    {        sign = "+";    }    s = sign + digits;    if (s.Length >= width)    {        return s; // 너비보다 길면 자르지 않는다    }    if (zero)    {        return sign + digits.PadLeft(width - sign.Length, "0"); // 0은 부호 뒤에 채운다    }    if (align == "<")    {        return s.PadRight(width);    }    if (align == "^")    {        left = Mathf.Quot(width - s.Length, 2);        return (" ".Repeat(left) + s).PadRight(width);    }    return s.PadLeft(width);} tmpl = Console.ReadLine();lits = [];specs = [];rest = tmpl;open = rest.IndexOf("{");while (open >= 0){    close = rest.IndexOf("}");    lits.Add(rest.Substring(0, open));    specs.Add(rest.Substring(open + 1, close - open - 1));    rest = rest.Substring(close + 1);    open = rest.IndexOf("{");}lits.Add(rest);n = Console.ReadLine().ToNumber();for (r = 0; r < n; r++){    vs = Console.ReadNumbers();    line = "";    for (k = 0; k < specs.Count; k++)    {        line = line + lits[k] + 서식(vs[k], specs[k]);    }    Console.WriteLine(line + lits[specs.Count]);}