学习 › TypeScript
数据 · 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、Craykon 没有这种类型,一个字符也只是长度为 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) |
常见错误
给单字符的字符串加 1Python · JavaScript · TypeScript · Craykon
print("a" + 1)→ Python 报 TypeError: can only concatenate str (not "int") to str。JavaScript、TypeScript、Craykon 不报错,得到 a1 — 把数接在后面
先转成编码再加,然后转回字符:Python chr(ord("a") + 1),JavaScript String.fromCharCode("a".charCodeAt(0) + 1),Craykon 字符.从编码(字符.编码("a") + 1)。
给字符加 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)开始是连续的。
各语言的差异
重复很容易和乘法混淆。
Python 中
JavaScript 正相反,
C++ 的
如果顺序写反成
重复很容易和乘法混淆。
Python 中
"3" * 2 不是 6 而是 "33",所以没把输入转成数就去乘,会变成字符串重复。JavaScript 正相反,
"3" * 2 是 6;TypeScript 是编译错误;Craykon 会提示“* 运算只能用于两个数”并停止。C++ 的
std::string(3, '*') 个数在前。如果顺序写反成
std::string('*', 3),不会报错,却得到一个莫名其妙的 42 个字符的字符串('*' 的编码是 42)。