文字を数として扱う方法が分かれます。 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 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.つなぐ(" ")); }}