데이터 · 11
문자 하나 다루기
글자 하나를 값으로: 코드, 글자 계산, i번째 글자, 되풀이.
글자 하나도 값이에요.
속으로는 수(코드)라서 더하고 뺄 수 있어요.
아래 예제는 소문자 하나와 숫자 하나가 번갈아 나오는 c2a3z1 같은 문자열을 두 글자씩 읽어서, 글자와 그 코드, 알파벳에서 다음 글자, 그리고 그 글자를 숫자만큼 되풀이한 문자열을 한 줄씩 찍어요.
s = input()for i in range(0, len(s), 2): ch = s[i] # i번째 글자 count = int(s[i + 1]) # 숫자 글자 → 수 code = ord(ch) after = chr(ord("a") + (code - ord("a") + 1) % 26) # 다음 글자(z 다음은 a) print(ch, code, after, ch * count)const s = require("fs").readFileSync(0, "utf8").trim();const a = "a".charCodeAt(0);for (let i = 0; i < s.length; i += 2) { const ch = s[i]; // i번째 글자 const count = Number(s[i + 1]); // 숫자 글자 → 수 const code = ch.charCodeAt(0); const after = String.fromCharCode(a + ((code - a + 1) % 26)); // 다음 글자(z 다음은 a) console.log(ch, code, after, ch.repeat(count));}import { readFileSync } from "node:fs";const s: string = readFileSync(0, "utf8").trim();const a: number = "a".charCodeAt(0);for (let i = 0; i < s.length; i += 2) { const ch: string = s[i]; // i번째 글자 const count: number = Number(s[i + 1]); // 숫자 글자 → 수 const code: number = ch.charCodeAt(0); const after: string = String.fromCharCode(a + ((code - a + 1) % 26)); // 다음 글자(z 다음은 a) console.log(ch, code, after, ch.repeat(count));}import java.util.Scanner; public class Main { public static void main(String[] args) { String s = new Scanner(System.in).next(); for (int i = 0; i < s.length(); i += 2) { char ch = s.charAt(i); // i번째 글자 int count = s.charAt(i + 1) - '0'; // 숫자 글자 → 수 int code = ch; char after = (char) ('a' + (ch - 'a' + 1) % 26); // 다음 글자(z 다음은 a) System.out.println(ch + " " + code + " " + after + " " + String.valueOf(ch).repeat(count)); } }}using System; class Program{ static void Main() { string s = Console.ReadLine().Trim(); for (int i = 0; i < s.Length; i += 2) { char ch = s[i]; // i번째 글자 int count = s[i + 1] - '0'; // 숫자 글자 → 수 int code = ch; char after = (char)('a' + (ch - 'a' + 1) % 26); // 다음 글자(z 다음은 a) Console.WriteLine($"{ch} {code} {after} {new string(ch, count)}"); } }}#include <iostream>#include <string> int main() { std::string s; std::cin >> s; for (size_t i = 0; i < s.size(); i += 2) { char ch = s[i]; // i번째 글자 int count = s[i + 1] - '0'; // 숫자 글자 → 수 int code = ch; char after = 'a' + (ch - 'a' + 1) % 26; // 다음 글자(z 다음은 a) std::cout << ch << ' ' << code << ' ' << after << ' ' << std::string(count, ch) << '\n'; }}#include <stdio.h>#include <string.h> int main(void) { char s[101]; scanf("%100s", s); int len = strlen(s); for (int i = 0; i < len; i += 2) { char ch = s[i]; // i번째 글자 int count = s[i + 1] - '0'; // 숫자 글자 → 수 int code = ch; char after = 'a' + (ch - 'a' + 1) % 26; // 다음 글자(z 다음은 a) printf("%c %d %c ", ch, code, after); for (int k = 0; k < count; k++) putchar(ch); // 되풀이는 반복문으로 printf("\n"); } return 0;}s = 콘솔.줄읽기().공백제거();a = 글자.코드("a");반복 (i = 0; i < s.길이; i += 2){ ch = s[i]; // i번째 글자 count = s[i + 1].수로변환(); // 숫자 글자 → 수 code = 글자.코드(ch); after = 글자.글자로변환(a + (code - a + 1) % 26); // 다음 글자(z 다음은 a) 콘솔.쓰기(ch + " " + code + " " + after + " " + ch.되풀이(count));}c2a3z1
c 99 d cc a 97 b aaa z 122 a z
핵심
- C·C++·Java·C#에는 글자 하나만 담는 타입
char가 있고, 작은따옴표로 써요('a').
Python·JavaScript·크레이콘에는 따로 없어서, 글자 하나도 길이가 1인 문자열이에요. - 글자 계산: 알파벳의 코드는 차례대로 이어져 있어요(
a97,b98, …).
그래서ch - 'a'는 a에서 몇 칸 뒤인지(0~25)이고,'a' + k는 a에서 k칸 뒤 글자예요.char가 없는 언어는 코드로 바꿔 계산한 뒤 글자로 되돌려요. - 숫자 글자는 수가 아니에요.
'7'의 코드는 55예요.
수 7을 얻으려면'0'의 코드를 빼거나('7' - '0'), 수로 바꾸는 함수를 써요. - i번째 글자는
s[i]로 꺼내요(Java는s.charAt(i)).
마지막 글자는길이 - 1번이에요.
그 너머를 읽으면 오류로 멈추는 언어, 조용히undefined를 주는 언어, 아예 확인하지 않아서 무슨 일이 생길지 정해져 있지 않은 언어(C·C++)로 갈려요. - 되풀이는 같은 문자열을 n번 이어 붙여요.
"ab"를 3번이면"ababab", 0번이면 빈 문자열이에요.
별 찍기나 줄 긋기를 반복문 없이 쓸 수 있어요.
언어별로 쓰는 법
| Python | 코드 ord(ch), 글자로 chr(n) — 다음 글자는 chr(ord(ch) + 1).숫자 글자는 int(ch).s[i], 뒤에서부터는 s[-1].범위 밖은 IndexError.되풀이는 ch * 3 |
|---|---|
| JavaScript | 코드 ch.charCodeAt(0), 글자로 String.fromCharCode(n).숫자 글자는 Number(ch).s[i], 뒤에서부터는 s.at(-1).범위 밖 s[9]는 오류 없이 undefined.되풀이는 ch.repeat(3) |
| TypeScript | JavaScript와 같아요 |
| Java | char ch = s.charAt(i) — s[i]는 못 써요.코드는 int code = ch, 글자로는 (char) (ch + 1).숫자 글자는 ch - '0'.범위 밖은 StringIndexOutOfBoundsException.되풀이는 문자열에만 있어서 String.valueOf(ch).repeat(3) |
| C# | char ch = s[i], 마지막은 s[^1].코드는 int code = ch, 글자로는 (char)(ch + 1).숫자 글자는 ch - '0'.범위 밖은 IndexOutOfRangeException.글자 되풀이는 new string(ch, 3) |
| C++ | char ch = s[i] — char가 곧 작은 정수라서 ch + 1, ch - '0'을 바로 써요.s[i]는 범위를 확인하지 않아서, 길이를 넘는 번호를 읽으면 정의되지 않은 동작이에요(엉뚱한 값이 나오거나 죽을 수 있어요).s.at(i)는 확인해서 std::out_of_range를 던져요.글자 되풀이는 std::string(3, ch)(개수가 먼저) |
| C | char ch = s[i] — C++처럼 char가 작은 정수예요.printf에서 %c는 글자로, %d는 코드로 찍어요.s[길이]에는 끝 표시 \0이 있고, 그 너머를 읽는 것은 확인도 없고 정의되지 않은 동작이에요(엉뚱한 값이 나오거나 죽을 수 있어요).되풀이는 없어서 반복문으로 찍어요 |
| Craykon | 코드 글자.코드(ch), 글자로 글자.글자로변환(n).숫자 글자는 ch.수로변환().s[i] — 범위 밖은 "문자열에는 0~2번만 있어요" 오류(음수 번호도 마찬가지).되풀이는 ch.되풀이(3) |
자주 하는 실수
글자에 1을 더해 찍었더니 수가 나왔어요Java · C# · C++
System.out.println('a' + 1); // Java
Console.WriteLine('a' + 1); // C#
std::cout << 'a' + 1; // C++→ 셋 다 98 — char에 수를 더하면 결과는 int예요
글자로 되돌려요: (char) ('a' + 1) → b.
Java·C#에서 char c = 'a'; c = c + 1;은 같은 이유로 컴파일 오류라서, c++나 c = (char) (c + 1)로 써요.
숫자 글자를 그대로 수로 썼어요C · C++ · Java · C#
char ch = '7';
int n = ch;
printf("%d\n", n);→ 55 — 7이 아니라 '7'의 코드예요
'0'을 빼요: ch - '0' → 7.
숫자 글자의 코드가 '0'(48)부터 차례로 이어져 있어서 돼요.
문자열 글자에 1을 더했어요Python · JavaScript · TypeScript · Craykon
print("a" + 1)→ Python은 TypeError: can only concatenate str (not "int") to str. JavaScript·TypeScript·크레이콘은 오류 없이 a1 — 수를 뒤에 이어 붙여요
코드로 바꿔 더한 뒤 글자로 되돌려요: Python chr(ord("a") + 1), JavaScript String.fromCharCode("a".charCodeAt(0) + 1), 크레이콘 글자.글자로변환(글자.코드("a") + 1).
언어마다 다른 점
되풀이는 곱셈과 헷갈리기 쉬워요.
Python에서
JavaScript는 반대로
C++
순서를 바꿔
되풀이는 곱셈과 헷갈리기 쉬워요.
Python에서
"3" * 2는 6이 아니라 "33"이라서, 입력을 수로 바꾸지 않고 곱하면 문자열 되풀이가 돼요.JavaScript는 반대로
"3" * 2가 6이고, TypeScript는 컴파일 오류, 크레이콘은 "* 계산은 수끼리만 할 수 있어요"라며 멈춰요.C++
std::string(3, '*')는 개수가 먼저예요.순서를 바꿔
std::string('*', 3)으로 쓰면 오류 없이 엉뚱한 42글자짜리 문자열이 돼요('*'의 코드가 42).