{ }codelper
文字型文字コードP0300

制御文字の表記をほどく

目に見えない文字を見える文字で書き表した文字列が t 個与えられる。
文字列を左から順に読みながら次の規則でほどき、ほどいた文字のコード(ASCII 番号)を求めよ。
\n はコード 10、\t はコード 9、\s はコード 32、\\(バックスラッシュ二つ)はコード 92 の文字一つになる。
\x のすぐ後ろの二文字がどちらも 16 進数の文字なら、この四文字はその二桁の 16 進数の値(0 ~ 255)をコードとする文字一つになる。
16 進数の文字は 0 ~ 9、a ~ f、A ~ F である。
^ の後ろに英大文字が続くと、^A はコード 1、^B はコード 2、…、^Z はコード 26 の文字一つになる。
^^ はコード 94 の文字(^)一つになる。
それ以外の文字はその文字のままで、コードはその文字の ASCII 番号である。
ほどいている途中で次のどれか一つにでも出会ったら、その文字列全体が誤りである。
\ の後ろに文字がないか、n、t、s、\、x 以外の文字が来る(\N のように大文字でも誤りである)。
\x の後ろに残っている文字が二つより少ないか、すぐ後ろの二文字の中に 16 進数の文字でないものがある。
^ の後ろに文字がないか、英大文字でも ^ でもない文字が来る(^a のように小文字でも誤りである)。
一行目に t が与えられ、続く t 行に文字列が一つずつ与えられる。
文字列ごとに一行に、ほどいた文字のコードを 10 進数で順に空白一つで区切って出力せよ。
誤りの文字列なら、コードの代わりに error だけを出力する。

入力
1 ≤ t ≤ 100。
文字列の長さは 1 以上 100 以下。
文字列は ASCII 番号 33 ~ 126 の文字だけからなる(空白はない)
出力
文字列ごとに一行:コードを空白一つで区切ったもの、または error
例 1 · stdin
5
Hi\n
^A^Z^^
\x41\xfF\\x
a\
\x4g
stdout
72 105 10
1 26 94
65 255 92 120
error
error
main.py
入力(stdin)

実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。

ほかの言語では?言語別の解答を見る · 8 言語の解答

文字を数として扱う方法が分かれます。
C・C++ の char は小さな整数で、Java・C# の char も数のように計算できるので、c - '0'、c - 'a' + 10、c - 'A' + 1 をそのまま書け、結果は int です。
Python には文字型がなく長さ 1 の文字列しかないので ord(c) - ord('a') と変換します('b' - 'a' は TypeError)。
JS・TS も c.charCodeAt(0) で変換します。
変換しないと "b" - "a" がエラーなしで NaN になります。
Craykon は 文字.コード(c) で、文字列どうしを引くと止まります。
範囲の確認は C 系が c >= 'a' && c <= 'f'、Python が 'a' <= c <= 'f'、JS・TS・Craykon は一文字の文字列どうしを >= で比べます。
バックスラッシュ一文字は八つの言語すべてで '\\' や "\\" のように二回書きます。
落とし穴 ① 16 進数の文字 a ~ f は c - 'a' に 10 を足し、大文字と小文字の両方を受け付けます。
② ^A は 0 ではなく 1 です(c - 'A' + 1)。
③ ^ の後ろが A ~ Z かどうか必ず範囲を確かめます。
確かめないと ^a が 33 になります。
④ 値は 255 まであります。
C・C++ の signed char と Java の byte は 127 までなので \xff が -1 になります。
C のただの char に符号があるかどうかは環境によって違います。
int に入れます。
⑤ 二文字を数に変える関数に任せると甘く受け付けます:JS の parseInt("4g", 16) は 4、parseInt("+f", 16) は 15、Python の int("+f", 16) は 15、int("-1", 16) は -1 です。
一文字ずつ自分で確かめます。
⑥ 行末の \ や ^ の後ろには文字がありません。
確かめずに次の文字を読むと、Java の charAt・C# の s[i]・Python の s[i]・Craykon はエラーで止まり、JS・TS は undefined を受け取り、C は文字列の終わりの '\0' を読みます(それより後ろは読んではいけません)。

Pythonmain.py · 57 行
import sys  def hex_value(c):    """16진수 글자 하나의 값(0 ~ 15). 16진수 글자가 아니면 -1"""    if "0" <= c <= "9":        return ord(c) - ord("0")    if "a" <= c <= "f":        return ord(c) - ord("a") + 10    if "A" <= c <= "F":        return ord(c) - ord("A") + 10    return -1  SIMPLE = {"n": 10, "t": 9, "s": 32, "\\": 92}  def decode(s):    """글자 코드 목록을 돌려준다. 잘못된 표기가 있으면 None"""    codes = []    i = 0    while i < len(s):        c = s[i]        nxt = s[i + 1] if i + 1 < len(s) else ""  # 뒤에 글자가 없으면 빈 문자열        if c == "\\":            if nxt in SIMPLE:                codes.append(SIMPLE[nxt])                i += 2            elif nxt == "x" and i + 3 < len(s):                hi, lo = hex_value(s[i + 2]), hex_value(s[i + 3])                if hi < 0 or lo < 0:                    return None                codes.append(hi * 16 + lo)                i += 4            else:                return None        elif c == "^":            if nxt == "^":                codes.append(ord("^"))            elif "A" <= nxt <= "Z":                codes.append(ord(nxt) - ord("A") + 1)            else:                return None            i += 2        else:            codes.append(ord(c))            i += 1    return codes  lines = sys.stdin.read().split("\n")t = int(lines[0])out = []for s in lines[1:1 + t]:    codes = decode(s.strip())    out.append("error" if codes is None else " ".join(map(str, codes)))print("\n".join(out))
JavaScriptmain.js · 53 行
const lines = require("fs").readFileSync(0, "utf8").split("\n"); const code = (c) => c.charCodeAt(0); // 16진수 글자 하나의 값(0 ~ 15). 16진수 글자가 아니면 -1function hexValue(c) {  if (c >= "0" && c <= "9") return code(c) - code("0");  if (c >= "a" && c <= "f") return code(c) - code("a") + 10;  if (c >= "A" && c <= "F") return code(c) - code("A") + 10;  return -1;} const SIMPLE = { n: 10, t: 9, s: 32, "\\": 92 }; // 글자 코드 배열을 돌려준다. 잘못된 표기가 있으면 nullfunction decode(s) {  const codes = [];  let i = 0;  while (i < s.length) {    const c = s[i];    const next = i + 1 < s.length ? s[i + 1] : ""; // 뒤에 글자가 없으면 빈 문자열    if (c === "\\") {      if (Object.hasOwn(SIMPLE, next)) {        codes.push(SIMPLE[next]);        i += 2;      } else if (next === "x" && i + 3 < s.length) {        const hi = hexValue(s[i + 2]), lo = hexValue(s[i + 3]);        if (hi < 0 || lo < 0) return null;        codes.push(hi * 16 + lo);        i += 4;      } else {        return null;      }    } else if (c === "^") {      if (next === "^") codes.push(code("^"));      else if (next >= "A" && next <= "Z") codes.push(code(next) - code("A") + 1);      else return null;      i += 2;    } else {      codes.push(code(c));      i += 1;    }  }  return codes;} const t = Number(lines[0]);const out = [];for (let k = 1; k <= t; k++) {  const codes = decode(lines[k].trim());  out.push(codes === null ? "error" : codes.join(" "));}console.log(out.join("\n"));
TypeScriptmain.ts · 56 行
import { readFileSync } from "node:fs"; const lines: string[] = readFileSync(0, "utf8").split("\n"); const code = (c: string): number => c.charCodeAt(0); // 16진수 글자 하나의 값(0 ~ 15). 16진수 글자가 아니면 -1function hexValue(c: string): number {  if (c >= "0" && c <= "9") return code(c) - code("0");  if (c >= "a" && c <= "f") return code(c) - code("a") + 10;  if (c >= "A" && c <= "F") return code(c) - code("A") + 10;  return -1;} const SIMPLE = new Map<string, number>([["n", 10], ["t", 9], ["s", 32], ["\\", 92]]); // 글자 코드 배열을 돌려준다. 잘못된 표기가 있으면 nullfunction decode(s: string): number[] | null {  const codes: number[] = [];  let i = 0;  while (i < s.length) {    const c = s[i];    const next = i + 1 < s.length ? s[i + 1] : ""; // 뒤에 글자가 없으면 빈 문자열    if (c === "\\") {      const simple = SIMPLE.get(next);      if (simple !== undefined) {        codes.push(simple);        i += 2;      } else if (next === "x" && i + 3 < s.length) {        const hi = hexValue(s[i + 2]), lo = hexValue(s[i + 3]);        if (hi < 0 || lo < 0) return null;        codes.push(hi * 16 + lo);        i += 4;      } else {        return null;      }    } else if (c === "^") {      if (next === "^") codes.push(code("^"));      else if (next >= "A" && next <= "Z") codes.push(code(next) - code("A") + 1);      else return null;      i += 2;    } else {      codes.push(code(c));      i += 1;    }  }  return codes;} const t = Number(lines[0]);const out: string[] = [];for (let k = 1; k <= t; k++) {  const codes = decode(lines[k].trim());  out.push(codes === null ? "error" : codes.join(" "));}console.log(out.join("\n"));
JavaMain.java · 60 行
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader; public class Main {    // 16진수 글자 하나의 값(0 ~ 15). 16진수 글자가 아니면 -1    static int hexValue(char c) {        if (c >= '0' && c <= '9') return c - '0'; // char끼리 빼면 int가 된다        if (c >= 'a' && c <= 'f') return c - 'a' + 10;        if (c >= 'A' && c <= 'F') return c - 'A' + 10;        return -1;    }     // 글자 코드를 빈칸으로 이어 돌려준다. 잘못된 표기가 있으면 null    static String decode(String s) {        StringBuilder codes = new StringBuilder();        int n = s.length(), i = 0;        while (i < n) {            char c = s.charAt(i);            char next = i + 1 < n ? s.charAt(i + 1) : '\0'; // 뒤에 글자가 없으면 코드 0인 글자            int value;            if (c == '\\') {                if (next == 'n') { value = '\n'; i += 2; }                else if (next == 't') { value = '\t'; i += 2; }                else if (next == 's') { value = ' '; i += 2; }                else if (next == '\\') { value = '\\'; i += 2; }                else if (next == 'x' && i + 3 < n) {                    int hi = hexValue(s.charAt(i + 2)), lo = hexValue(s.charAt(i + 3));                    if (hi < 0 || lo < 0) return null;                    value = hi * 16 + lo;                    i += 4;                } else {                    return null;                }            } else if (c == '^') {                if (next == '^') value = '^';                else if (next >= 'A' && next <= 'Z') value = next - 'A' + 1;                else return null;                i += 2;            } else {                value = c; // char는 int로 저절로 넓어진다                i += 1;            }            if (codes.length() > 0) codes.append(' ');            codes.append(value);        }        return codes.toString();    }     public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        int t = Integer.parseInt(in.readLine().trim());        StringBuilder out = new StringBuilder();        for (int k = 0; k < t; k++) {            String codes = decode(in.readLine().trim());            out.append(codes == null ? "error" : codes).append('\n');        }        System.out.print(out);    }}
C#Main.cs · 67 行
using System;using System.Collections.Generic;using System.Text; class Program{    // 16진수 글자 하나의 값(0 ~ 15). 16진수 글자가 아니면 -1    static int HexValue(char c)    {        if (c >= '0' && c <= '9') return c - '0'; // char끼리 빼면 int가 된다        if (c >= 'a' && c <= 'f') return c - 'a' + 10;        if (c >= 'A' && c <= 'F') return c - 'A' + 10;        return -1;    }     // 글자 코드 목록을 돌려준다. 잘못된 표기가 있으면 null    static List<int> Decode(string s)    {        var codes = new List<int>();        int n = s.Length, i = 0;        while (i < n)        {            char c = s[i];            char next = i + 1 < n ? s[i + 1] : '\0'; // 뒤에 글자가 없으면 코드 0인 글자            if (c == '\\')            {                if (next == 'n') { codes.Add('\n'); i += 2; }                else if (next == 't') { codes.Add('\t'); i += 2; }                else if (next == 's') { codes.Add(' '); i += 2; }                else if (next == '\\') { codes.Add('\\'); i += 2; }                else if (next == 'x' && i + 3 < n)                {                    int hi = HexValue(s[i + 2]), lo = HexValue(s[i + 3]);                    if (hi < 0 || lo < 0) return null;                    codes.Add(hi * 16 + lo);                    i += 4;                }                else return null;            }            else if (c == '^')            {                if (next == '^') codes.Add('^');                else if (next >= 'A' && next <= 'Z') codes.Add(next - 'A' + 1);                else return null;                i += 2;            }            else            {                codes.Add(c); // char는 int로 저절로 넓어진다                i += 1;            }        }        return codes;    }     static void Main()    {        int t = int.Parse(Console.ReadLine().Trim());        var output = new StringBuilder();        for (int k = 0; k < t; k++)        {            List<int> codes = Decode(Console.ReadLine().Trim());            output.Append(codes == null ? "error" : string.Join(" ", codes)).Append('\n');        }        Console.Write(output);    }}
C++main.cpp · 62 行
#include <iostream>#include <optional>#include <string>#include <vector> // 16진수 글자 하나의 값(0 ~ 15). 16진수 글자가 아니면 -1int hexValue(char c) {    if (c >= '0' && c <= '9') return c - '0'; // char는 작은 정수라서 바로 뺄 수 있다    if (c >= 'a' && c <= 'f') return c - 'a' + 10;    if (c >= 'A' && c <= 'F') return c - 'A' + 10;    return -1;} // 글자 코드들을 돌려준다. 잘못된 표기가 있으면 값이 없다(std::nullopt)std::optional<std::vector<int>> decode(const std::string& s) {    std::vector<int> codes;    const std::size_t n = s.size();    std::size_t i = 0;    while (i < n) {        const char c = s[i];        const char next = i + 1 < n ? s[i + 1] : '\0'; // 뒤에 글자가 없으면 코드 0인 글자        if (c == '\\') {            if (next == 'n') { codes.push_back('\n'); i += 2; }            else if (next == 't') { codes.push_back('\t'); i += 2; }            else if (next == 's') { codes.push_back(' '); i += 2; }            else if (next == '\\') { codes.push_back('\\'); i += 2; }            else if (next == 'x' && i + 3 < n) {                const int hi = hexValue(s[i + 2]), lo = hexValue(s[i + 3]);                if (hi < 0 || lo < 0) return std::nullopt;                codes.push_back(hi * 16 + lo); // 255까지라 char가 아니라 int에 담는다                i += 4;            } else {                return std::nullopt;            }        } else if (c == '^') {            if (next == '^') codes.push_back('^');            else if (next >= 'A' && next <= 'Z') codes.push_back(next - 'A' + 1);            else return std::nullopt;            i += 2;        } else {            codes.push_back(c);            i += 1;        }    }    return codes;} int main() {    int t;    std::cin >> t;    while (t-- > 0) {        std::string s;        std::cin >> s;        const auto codes = decode(s);        if (!codes) {            std::cout << "error\n";            continue;        }        for (std::size_t i = 0; i < codes->size(); i++) std::cout << (i ? " " : "") << (*codes)[i];        std::cout << '\n';    }}
Cmain.c · 60 行
#include <stdio.h>#include <string.h> /* 16진수 글자 하나의 값(0 ~ 15). 16진수 글자가 아니면 -1 */static int hex_value(char c) {    if (c >= '0' && c <= '9') return c - '0'; /* char는 작은 정수라서 바로 뺄 수 있다 */    if (c >= 'a' && c <= 'f') return c - 'a' + 10;    if (c >= 'A' && c <= 'F') return c - 'A' + 10;    return -1;} /* codes에 글자 코드를 채우고 개수를 돌려준다. 잘못된 표기가 있으면 -1 */static int decode(const char *s, int *codes) {    int n = (int)strlen(s), count = 0, i = 0;    while (i < n) {        char c = s[i];        char next = s[i + 1]; /* 뒤에 글자가 없으면 문자열 끝의 '\0' */        if (c == '\\') {            if (next == 'n') { codes[count++] = '\n'; i += 2; }            else if (next == 't') { codes[count++] = '\t'; i += 2; }            else if (next == 's') { codes[count++] = ' '; i += 2; }            else if (next == '\\') { codes[count++] = '\\'; i += 2; }            else if (next == 'x' && i + 3 < n) {                int hi = hex_value(s[i + 2]), lo = hex_value(s[i + 3]);                if (hi < 0 || lo < 0) return -1;                codes[count++] = hi * 16 + lo; /* 255까지라 char가 아니라 int에 담는다 */                i += 4;            } else {                return -1;            }        } else if (c == '^') {            if (next == '^') codes[count++] = '^';            else if (next >= 'A' && next <= 'Z') codes[count++] = next - 'A' + 1;            else return -1;            i += 2;        } else {            codes[count++] = c;            i += 1;        }    }    return count;} int main(void) {    int t;    scanf("%d", &t);    while (t-- > 0) {        char s[101];        int codes[100];        scanf("%100s", s);        int count = decode(s, codes);        if (count < 0) {            printf("error\n");            continue;        }        for (int i = 0; i < count; i++) printf(i ? " %d" : "%d", codes[i]);        printf("\n");    }    return 0;}
Craykonmain.cray · 109 行
// 16진수 글자 하나의 값(0 ~ 15). 16진수 글자가 아니면 -1십육진값(c){    もし (c >= "0" && c <= "9")    {        返す 文字.コード(c) - 文字.コード("0");    }    もし (c >= "a" && c <= "f")    {        返す 文字.コード(c) - 文字.コード("a") + 10;    }    もし (c >= "A" && c <= "F")    {        返す 文字.コード(c) - 文字.コード("A") + 10;    }    返す -1;} // 글자 코드 목록을 돌려준다. 잘못된 표기가 있으면 빈값풀기(s){    codes = [];    n = s.長さ;    i = 0;    間 (i < n)    {        c = s[i];        // 뒤에 글자가 없으면 빈 문자열        next = "";        もし (i + 1 < n)        {            next = s[i + 1];        }        もし (c == "\\")        {            もし (next == "n")            {                codes.追加(10);                i += 2;            }            でなければ もし (next == "t")            {                codes.追加(9);                i += 2;            }            でなければ もし (next == "s")            {                codes.追加(32);                i += 2;            }            でなければ もし (next == "\\")            {                codes.追加(92);                i += 2;            }            でなければ もし (next == "x" && i + 3 < n)            {                hi = 십육진값(s[i + 2]);                lo = 십육진값(s[i + 3]);                もし (hi < 0 || lo < 0)                {                    返す なし;                }                codes.追加(hi * 16 + lo);                i += 4;            }            でなければ            {                返す なし;            }        }        でなければ もし (c == "^")        {            もし (next == "^")            {                codes.追加(文字.コード("^"));            }            でなければ もし (next >= "A" && next <= "Z")            {                codes.追加(文字.コード(next) - 文字.コード("A") + 1);            }            でなければ            {                返す なし;            }            i += 2;        }        でなければ        {            codes.追加(文字.コード(c));            i += 1;        }    }    返す codes;} t = コンソール.行読み().数に();繰り返す (k = 0; k < t; k++){    codes = 풀기(コンソール.行読み().空白除去());    もし (codes == なし)    {        コンソール.書く("error");    }    でなければ    {        コンソール.書く(codes.つなぐ(" "));    }}