{ }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.長さ;    }}// 왼쪽 맞춤이 뒤집히면 오른쪽 맞춤이 된다それぞれ (줄 の中 거울){    コンソール.書く(줄.前埋め(너비));}