눈에 보이지 않는 글자를 보이는 글자로 적은 문자열이 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
오류 목록00F8 ↓ · ⇧F8 ↑
입력(stdin)
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 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이 돼요. 크레이콘은 글자.코드(c)이고 문자열끼리 빼면 멈춰요. 범위 확인은 C 계열 c >= 'a' && c <= 'f', Python 'a' <= c <= 'f', JS·TS·크레이콘은 한 글자 문자열끼리 >=로 견줘요. 역슬래시 한 글자는 여덟 언어 모두 '\\'나 "\\"처럼 두 번 써요. 함정 ① 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]·크레이콘은 오류로 멈추고, JS·TS는 undefined를 받고, C는 문자열 끝의 '\0'을 읽어요(그보다 더 뒤는 읽으면 안 돼요).
Pythonmain.py · 57 줄
import sysdef 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 -1SIMPLE = {"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 codeslines = 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.잇기(" ")); }}