{ }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()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 8 种语言题解

反转:Python s[::-1],Java new StringBuilder(s).reverse(),C# 对字符数组 Array.Reverse 后 new string(c),C++ std::reverse(s.begin(), s.end()),Craykon 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,Craykon s.替换(a, b)。
C 没有替换函数,所以在从两端交换来反转时顺便换成配对字符最自然。
反斜杠在字符串里要写两次 "\\" 才是一个字符(所有语言都一样,Craykon 也是)。
右对齐要等所有行都做完才知道最长长度,所以先把行存起来最后再输出。
在前面补空格:Python s.rjust(L),JS·TS s.padStart(L),C# s.PadLeft(L),C printf("%*s", L, s),Craykon 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.长度;    }}// 왼쪽 맞춤이 뒤집히면 오른쪽 맞춤이 된다遍历 (줄 在 거울){    控制台.输出(줄.左填充(너비));}