{ }codelper
문자열 뒤집기문자열 바꾸기자리 맞추기P0174

유리창에 붙일 거울 글씨

가게 유리문 안쪽에 안내문을 붙이면, 밖에서는 좌우가 뒤집힌 모양으로 보인다. 그래서 안쪽에서 붙일 거울 글씨를 미리 만들어, 밖에서 바르게 읽히게 하려고 한다. 첫 줄에 줄 수 n이 주어지고, 다음 n줄에 안내문이 한 줄씩 주어진다.
안내문은 왼쪽 맞춤으로 쓰여 있다. 안내문의 줄마다 거울 글씨를 만들어 입력과 같은 차례로 출력한다.
줄의 차례는 바꾸지 않는다. 거울 글씨는 먼저 그 줄의 글자 차례를 맨 끝부터 맨 앞까지 거꾸로 뒤집은 것이다. 그다음, 거울에 비치면 서로 모양이 바뀌는 글자를 짝끼리 맞바꾼다. 짝은 ( 와 ), [ 와 ], { 와 }, < 와 >, / 와 \, 소문자 b 와 d, 소문자 p 와 q 의 일곱 쌍이다. 예를 들어 ( 는 ) 가 되고 ) 는 ( 가 된다.
짝이 없는 글자(빈칸, 숫자, 대문자, 다른 글자)는 그대로 둔다. 왼쪽 맞춤인 글을 좌우로 뒤집으면 오른쪽 맞춤이 된다.
그래서 가장 긴 줄의 길이를 L이라 하면, 줄마다 앞에 빈칸을 (L − 그 줄의 길이)개 붙여 출력한다.
가장 긴 줄에는 빈칸을 붙이지 않는다.

입력
1 ≤ n ≤ 50.
줄마다 길이 1 ~ 200이고 ASCII 글자(코드 32~126)만 쓰며, 맨 앞과 맨 끝은 빈칸이 아니다
출력
n줄
예시 1 · stdin
3
(open) 9-18
<- push door
bread & pie
stdout
 81-9 (neqo)
roob hsuq ->
 eiq & baerd
예시 2 · stdin
2
a/b\c
[sale] {today}
stdout
         c/d\a
{yabot} [elas]
main.py
입력(stdin)

실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이

뒤집기는 Python s[::-1], Java new StringBuilder(s).reverse(), C# 글자 배열을 Array.Reverse 한 뒤 new string(c), C++ std::reverse(s.begin(), s.end()), 크레이콘 s.뒤집기()예요.
JS·TS 문자열에는 reverse가 없어서 [...s].reverse().join("")처럼 배열을 거쳐요.
함정은 맞바꾸기예요.
s.replace("(", ")").replace(")", "(")처럼 차례로 바꾸면 처음에 바꾼 ) 까지 다시 ( 가 되어 둘 다 ( 로 남아요.
입력은 코드 32~126 글자만 쓰니, 입력에 나올 수 없는 글자(여기서는 코드 1)에 한쪽을 잠깐 맡겨 두고 세 번 바꾸면 돼요: a → 맡김, b → a, 맡김 → b.
글자를 하나씩 보며 짝이 있으면 짝으로 바꿔 새 문자열에 붙이는 한 번 훑기도 똑같이 맞아요.
모두 바꾸기는 Python replace, JS replaceAll(TS는 split(a).join(b)도 흔해요), Java replace(char, char), C# Replace(char, char), C++ <algorithm>의 std::replace, 크레이콘 s.바꾸기(a, b)예요.
C에는 바꾸기 함수가 없어서, 양 끝에서 맞바꾸며 뒤집을 때 짝 글자로 바꿔 넣는 게 자연스러워요.
역슬래시는 문자열 안에서 "\\"처럼 두 번 써야 한 글자예요(모든 언어 공통, 크레이콘도 같아요).
오른쪽 맞춤은 모든 줄을 다 만든 뒤에야 가장 긴 길이를 알 수 있어서, 줄을 모아 두었다가 출력해요.
앞을 채우는 것은 Python s.rjust(L), JS·TS s.padStart(L), C# s.PadLeft(L), C printf("%*s", L, s), 크레이콘 s.앞채우기(L)이고, Java·C++는 빈칸 (L − 길이)개를 앞에 붙여요(Java " ".repeat(k), C++ std::string(k, ' ')).
뒤를 채우면(padEnd) 줄 끝 빈칸이라 왼쪽 맞춤 그대로예요.
거울은 좌우만 뒤집으니 줄의 차례까지 뒤집으면 안 돼요.

Pythonmain.py · 19 줄
TMP = "\x01"  # 입력에 나오지 않는 글자(입력은 코드 32~126만 쓴다)를 잠깐 맡아 두는 자리로 쓴다PAIRS = [("(", ")"), ("[", "]"), ("{", "}"), ("<", ">"), ("/", "\\"), ("b", "d"), ("p", "q")]  def swap(s, a, b):    """s 안의 a와 b를 서로 맞바꾼다. a → b, b → a를 차례로 하면 둘 다 a가 되어 버린다."""    return s.replace(a, TMP).replace(b, a).replace(TMP, b)  n = int(input())out = []for _ in range(n):    s = input()[::-1]  # 좌우를 뒤집는다(줄의 차례는 그대로)    for a, b in PAIRS:        s = swap(s, a, b)    out.append(s) width = max(len(s) for s in out)  # 왼쪽 맞춤이 뒤집히면 오른쪽 맞춤이 된다print("\n".join(s.rjust(width) for s in out))
JavaScriptmain.js · 17 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);const TMP = "\x01"; // 입력에 나오지 않는 글자(입력은 코드 32~126만 쓴다)를 잠깐 맡아 두는 자리로 쓴다const PAIRS = [["(", ")"], ["[", "]"], ["{", "}"], ["<", ">"], ["/", "\\"], ["b", "d"], ["p", "q"]]; // s 안의 a와 b를 서로 맞바꾼다. a → b, b → a를 차례로 하면 둘 다 a가 되어 버린다const swap = (s, a, b) => s.replaceAll(a, TMP).replaceAll(b, a).replaceAll(TMP, b); const out = [];for (let k = 1; k <= n; k++) {  let s = [...lines[k]].reverse().join(""); // 문자열에는 reverse가 없어 배열로 뒤집는다  for (const [a, b] of PAIRS) s = swap(s, a, b);  out.push(s);}// 왼쪽 맞춤이 뒤집히면 오른쪽 맞춤이 된다const width = Math.max(...out.map((s) => s.length));console.log(out.map((s) => s.padStart(width)).join("\n"));
TypeScriptmain.ts · 19 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const n: number = Number(lines[0]);const TMP = "\x01"; // 입력에 나오지 않는 글자(입력은 코드 32~126만 쓴다)를 잠깐 맡아 두는 자리로 쓴다const PAIRS: [string, string][] = [["(", ")"], ["[", "]"], ["{", "}"], ["<", ">"], ["/", "\\"], ["b", "d"], ["p", "q"]]; // s 안의 a와 b를 서로 맞바꾼다. a → b, b → a를 차례로 하면 둘 다 a가 되어 버린다const swap = (s: string, a: string, b: string): string =>  s.split(a).join(TMP).split(b).join(a).split(TMP).join(b); const out: string[] = [];for (let k = 1; k <= n; k++) {  let s: string = [...lines[k]].reverse().join(""); // 문자열에는 reverse가 없어 배열로 뒤집는다  for (const [a, b] of PAIRS) s = swap(s, a, b);  out.push(s);}// 왼쪽 맞춤이 뒤집히면 오른쪽 맞춤이 된다const width: number = Math.max(...out.map((s) => s.length));console.log(out.map((s) => s.padStart(width)).join("\n"));
JavaMain.java · 31 줄
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader; public class Main {    static final char TMP = '\u0001'; // 입력에 나오지 않는 글자(입력은 코드 32~126만 쓴다)를 잠깐 맡아 두는 자리로 쓴다    static final String PAIRS = "()[]{}<>/\\bdpq"; // 두 글자씩 짝     public static void main(String[] args) throws IOException {        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        int n = Integer.parseInt(br.readLine().trim());        String[] mirrored = new String[n];        int width = 0;        for (int k = 0; k < n; k++) {            String s = new StringBuilder(br.readLine()).reverse().toString(); // 좌우를 뒤집는다            for (int i = 0; i < PAIRS.length(); i += 2) {                char a = PAIRS.charAt(i), b = PAIRS.charAt(i + 1);                // a → b, b → a를 차례로 하면 둘 다 a가 되므로 잠깐 TMP에 맡긴다                s = s.replace(a, TMP).replace(b, a).replace(TMP, b);            }            mirrored[k] = s;            width = Math.max(width, s.length());        }        // 왼쪽 맞춤이 뒤집히면 오른쪽 맞춤이 된다        StringBuilder out = new StringBuilder();        for (String s : mirrored) {            out.append(" ".repeat(width - s.length())).append(s).append('\n');        }        System.out.print(out);    }}
C#Main.cs · 33 줄
using System;using System.Text; class Program{    const char Tmp = '\u0001'; // 입력에 나오지 않는 글자(입력은 코드 32~126만 쓴다)를 잠깐 맡아 두는 자리로 쓴다    const string Pairs = "()[]{}<>/\\bdpq"; // 두 글자씩 짝     static void Main()    {        int n = int.Parse(Console.ReadLine().Trim());        var mirrored = new string[n];        int width = 0;        for (int k = 0; k < n; k++)        {            char[] c = Console.ReadLine().ToCharArray();            Array.Reverse(c); // 좌우를 뒤집는다            string s = new string(c);            for (int i = 0; i < Pairs.Length; i += 2)            {                char a = Pairs[i], b = Pairs[i + 1];                // a → b, b → a를 차례로 하면 둘 다 a가 되므로 잠깐 Tmp에 맡긴다                s = s.Replace(a, Tmp).Replace(b, a).Replace(Tmp, b);            }            mirrored[k] = s;            width = Math.Max(width, s.Length);        }        // 왼쪽 맞춤이 뒤집히면 오른쪽 맞춤이 된다        var sb = new StringBuilder();        foreach (string s in mirrored) sb.Append(s.PadLeft(width)).Append('\n');        Console.Write(sb);    }}
C++main.cpp · 32 줄
#include <algorithm>#include <iostream>#include <string>#include <vector> int main() {    const char tmp = '\x01'; // 입력에 나오지 않는 글자(입력은 코드 32~126만 쓴다)를 잠깐 맡아 두는 자리로 쓴다    const std::string pairs = "()[]{}<>/\\bdpq"; // 두 글자씩 짝    int n;    std::cin >> n;    std::string s;    std::getline(std::cin, s); // n 뒤의 줄바꿈을 버린다    std::vector<std::string> mirrored;    std::size_t width = 0;    for (int k = 0; k < n; k++) {        std::getline(std::cin, s);        std::reverse(s.begin(), s.end()); // 좌우를 뒤집는다        for (std::size_t i = 0; i < pairs.size(); i += 2) {            char a = pairs[i], b = pairs[i + 1];            // a → b, b → a를 차례로 하면 둘 다 a가 되므로 잠깐 tmp에 맡긴다            std::replace(s.begin(), s.end(), a, tmp);            std::replace(s.begin(), s.end(), b, a);            std::replace(s.begin(), s.end(), tmp, b);        }        width = std::max(width, s.size());        mirrored.push_back(s);    }    // 왼쪽 맞춤이 뒤집히면 오른쪽 맞춤이 된다    for (const std::string& line : mirrored) {        std::cout << std::string(width - line.size(), ' ') << line << '\n';    }}
Cmain.c · 35 줄
#include <stdio.h>#include <string.h> /* 짝이 있는 글자는 짝으로, 없는 글자는 그대로 돌려준다 */static char mirror(char ch) {    static const char pairs[] = "()[]{}<>/\\bdpq"; /* 두 글자씩 짝 */    const char *p = strchr(pairs, ch);    if (p == NULL || ch == '\0') return ch;    int i = (int)(p - pairs);    return i % 2 == 0 ? pairs[i + 1] : pairs[i - 1];} int main(void) {    int n, width = 0;    static char lines[50][256];    char buf[256];    fgets(buf, sizeof buf, stdin);    sscanf(buf, "%d", &n);    for (int k = 0; k < n; k++) {        char *line = lines[k];        fgets(line, sizeof lines[k], stdin);        line[strcspn(line, "\r\n")] = '\0';        int len = (int)strlen(line);        /* C에는 문자열 바꾸기가 없어서, 양 끝에서 맞바꾸며 뒤집을 때 짝 글자로도 바꾼다 */        for (int i = 0, j = len - 1; i <= j; i++, j--) {            char a = line[i], b = line[j];            line[i] = mirror(b);            line[j] = mirror(a);        }        if (len > width) width = len;    }    /* 왼쪽 맞춤이 뒤집히면 오른쪽 맞춤이 된다: %*s는 너비를 받아 앞을 빈칸으로 채운다 */    for (int k = 0; k < n; k++) printf("%*s\n", width, lines[k]);    return 0;}
Craykonmain.cray · 24 줄
맡김 = 글자.글자로변환(1); // 입력에 나오지 않는 글자(입력은 코드 32~126만 쓴다)를 잠깐 맡아 두는 자리로 쓴다짝 = ["(", ")", "[", "]", "{", "}", "<", ">", "/", "\\", "b", "d", "p", "q"]; // 두 개씩 짝n = 콘솔.줄읽기().수로변환();거울 = [];너비 = 0;반복 (k = 0; k < n; k += 1){    s = 콘솔.줄읽기().뒤집기(); // 좌우를 뒤집는다(줄의 차례는 그대로)    반복 (i = 0; i < 짝.개수; i += 2)    {        // a → b, b → a를 차례로 하면 둘 다 a가 되므로 잠깐 맡김 글자에 맡긴다        s = s.바꾸기(짝[i], 맡김).바꾸기(짝[i + 1], 짝[i]).바꾸기(맡김, 짝[i + 1]);    }    거울.넣기(s);    만약 (s.길이 > 너비)    {        너비 = s.길이;    }}// 왼쪽 맞춤이 뒤집히면 오른쪽 맞춤이 된다각각 (줄 에서 거울){    콘솔.쓰기(줄.앞채우기(너비));}