{ }codelper
字符字符编码P0300

解开控制字符的写法

给出 t 个字符串,其中看不见的字符是用看得见的字符写出来的。
从左到右读每个字符串,按下面的规则解开,求出解开后各字符的编码(ASCII 编号)。
\n 变成编码 10 的一个字符,\t 是编码 9,\s 是编码 32,\\(两个反斜杠)是编码 92。
如果紧跟在 \x 后面的两个字符都是十六进制字符,这四个字符就变成以这个两位十六进制值(0 ~ 255)为编码的一个字符。
十六进制字符是 0 ~ 9、a ~ f、A ~ F。
^ 后面跟着英文大写字母时变成一个字符:^A 是编码 1,^B 是编码 2,…,^Z 是编码 26。
^^ 变成编码 94 的一个字符(^)。
其他字符保持原样,编码就是它的 ASCII 编号。
解开的过程中只要遇到下面任何一种情况,整个字符串就是错误的。
\ 后面没有字符,或者跟着 n、t、s、\、x 以外的字符(像 \N 这样的大写字母也是错误的)。
\x 后面剩下的字符不足两个,或者紧跟的两个字符中有不是十六进制字符的。
^ 后面没有字符,或者跟着既不是英文大写字母也不是 ^ 的字符(像 ^a 这样的小写字母也是错误的)。
第一行给出 t,接下来 t 行每行一个字符串。
对每个字符串输出一行,按顺序用十进制输出解开后各字符的编码,用一个空格隔开。
如果字符串是错误的,不输出编码,只输出 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 用 >= 比较单字符的字符串。
一个反斜杠在八种语言里都要写两次,如 '\\' 或 "\\"。
陷阱 ① 十六进制字母 a ~ f 要在 c - 'a' 上加 10,而且大小写都要接受。
② ^A 是 1 而不是 0(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.连接(" "));    }}