字符串
字符串
字符串概述
所谓字符串,顾名思义,就是由字符构成的数组,类似与字符排成了“一串”。
字符串是编程中最常用的数据类型之一,用于表示文本数据。它是由字符组成的序列,可以包含字母、数字、符号等各种字符,主要具有以下特点:
- 有序性:字符串中的字符按特定顺序排列,每个字符都有其位置(索引)
- 不可变性:在 Java 和 Python 语言中,字符串一旦创建就不能修改(任何修改都会创建新的字符串)
- 灵活性:可以存储各种文本数据,包括多语言文字、特殊符号等
- 丰富的操作:大多数编程语言都提供了丰富的字符串处理函数和方法
字符与 ASCII 码
字符是计算机中最基本的信息单位之一,通常以 ASCII码(American Standard Code for Information Interchange)的形式存储和表示。ASCII 码是一种将字符映射到数字的标准编码方式,它使用7位二进制数(0-127)来表示128个字符。下面给出一个 ASCII 码表的示例:
0 | \0 | 空字符(Null) | 64 | @ | at符号 |
1 | 标题开始(SOH) | 65 | A | 大写字母A | |
2 | 正文开始(STX) | 66 | B | 大写字母B | |
3 | 正文结束(ETX) | 67 | C | 大写字母C | |
4 | 传输结束(EOT) | 68 | D | 大写字母D | |
5 | 查询(ENQ) | 69 | E | 大写字母E | |
6 | 确认(ACK) | 70 | F | 大写字母F | |
7 | \a | 响铃(BEL) | 71 | G | 大写字母G |
8 | \b | 退格(BS) | 72 | H | 大写字母H |
9 | \t | 水平制表(HT) | 73 | I | 大写字母I |
10 | \n | 换行(LF) | 74 | J | 大写字母J |
11 | \v | 垂直制表(VT) | 75 | K | 大写字母K |
12 | \f | 换页(FF) | 76 | L | 大写字母L |
13 | \r | 回车(CR) | 77 | M | 大写字母M |
14 | 移出(SO) | 78 | N | 大写字母N | |
15 | 移入(SI) | 79 | O | 大写字母O | |
16 | 数据链路转义(DLE) | 80 | P | 大写字母P | |
17 | 设备控制1(DC1) | 81 | Q | 大写字母Q | |
18 | 设备控制2(DC2) | 82 | R | 大写字母R | |
19 | 设备控制3(DC3) | 83 | S | 大写字母S | |
20 | 设备控制4(DC4) | 84 | T | 大写字母T | |
21 | 否定应答(NAK) | 85 | U | 大写字母U | |
22 | 同步空闲(SYN) | 86 | V | 大写字母V | |
23 | 传输块结束(ETB) | 87 | W | 大写字母W | |
24 | 取消(CAN) | 88 | X | 大写字母X | |
25 | 媒体结束(EM) | 89 | Y | 大写字母Y | |
26 | 替换(SUB) | 90 | Z | 大写字母Z | |
27 | 转义(ESC) | 91 | [ | 左方括号 | |
28 | 文件分隔符(FS) | 92 | \ | 反斜杠 | |
29 | 组分隔符(GS) | 93 | ] | 右方括号 | |
30 | 记录分隔符(RS) | 94 | ^ | 脱字符 | |
31 | 单元分隔符(US) | 95 | _ | 下划线 | |
32 | 空格 | 空格 | 96 | ` | 反引号 |
33 | ! | 感叹号 | 97 | a | 小写字母a |
34 | " | 双引号 | 98 | b | 小写字母b |
35 | # | 井号 | 99 | c | 小写字母c |
36 | $ | 美元符号 | 100 | d | 小写字母d |
37 | % | 百分号 | 101 | e | 小写字母e |
38 | & | 与符号 | 102 | f | 小写字母f |
39 | ' | 单引号 | 103 | g | 小写字母g |
40 | ( | 左圆括号 | 104 | h | 小写字母h |
41 | ) | 右圆括号 | 105 | i | 小写字母i |
42 | * | 星号 | 106 | j | 小写字母j |
43 | + | 加号 | 107 | k | 小写字母k |
44 | , | 逗号 | 108 | l | 小写字母l |
45 | - | 连字符 | 109 | m | 小写字母m |
46 | . | 句号 | 110 | n | 小写字母n |
47 | / | 斜杠 | 111 | o | 小写字母o |
48 | 0 | 数字0 | 112 | p | 小写字母p |
49 | 1 | 数字1 | 113 | q | 小写字母q |
50 | 2 | 数字2 | 114 | r | 小写字母r |
51 | 3 | 数字3 | 115 | s | 小写字母s |
52 | 4 | 数字4 | 116 | t | 小写字母t |
53 | 5 | 数字5 | 117 | u | 小写字母u |
54 | 6 | 数字6 | 118 | v | 小写字母v |
55 | 7 | 数字7 | 119 | w | 小写字母w |
56 | 8 | 数字8 | 120 | x | 小写字母x |
57 | 9 | 数字9 | 121 | y | 小写字母y |
58 | : | 冒号 | 122 | z | 小写字母z |
59 | ; | 分号 | 123 | { | 左花括号 |
60 | < | 小于号 | 124 | | | 竖线 |
61 | = | 等号 | 125 | } | 右花括号 |
62 | > | 大于号 | 126 | ~ | 波浪号 |
63 | ? | 问号 | 127 | 删除(DEL) |
你不会以为我放这么大一张表格是让你背的吧!? 实际上,这个表格完全不需要背,你只需要大概有些印象就可以了。但是这个庞大的表格实在很难让人抓住重点,所以我再精简一下:
48~57 | 0 ~9 |
依次为数字字符 0 到字符 9 |
65~90 | A ~Z |
依次为大写字母 A 到字符 Z |
97~122 | a ~z |
依次为小写字母 a 到字符 z |
不难注意到一些性质:
-
如果我们把一个英文字母的 ASCII 码增加或减小
,在新的 ASCII 码不超出对应大/小写字母的 ASCII 码范围,那么这个字符会变成它对应的字母序增加或减小
的字符。例如,对字符
a
进行 ASCII 码加 1,就相当与把他变为他后面的下 1 个字母,即为b
。 -
如果我们把任意的一个大写字母的 ASCII 码增加
(即
a
的 ASCII 码减去A
的 ASCII 码)。则这个字符会变为它对应的小写字母。例如,对字符A
进行 ASCII 码加 32 的操作,就相当与把他变为他后面的下 32 个字母,即为a
。同理,如果我们把任意的一个小写字母的 ASCII 码减去(即
A
的 ASCII 码减去a
的 ASCII 码)。则这个字符会变为它对应的大写字母。例如,对字符a
进行 ASCII 码减的操作,就相当与把他变为他前面的上
个字母,即为
A
。 -
如果我们把任意的一个数字字符减去
(即
0
的 ASCII 码),那么此时的 ASCII 码数值就是原本数字字符的字面数值。例如,对字符1
进行 ASCII 码减的操作,则此时的 ASCII 码值则变为了
。这相当于一个将数字字符转化为对应数字的操作。
-
我们可以通过判断 ASCII 码的范围来确定一个字符是否为数字字符、大写字母或小写字母。例如,我们可以通过判断字符的 ASCII 码是否在
48
到57
之间来确定一个字符是否为数字字符。
接下来,我们将分语言,分别实现读入字符、求出对应 ASCII 码、小写字母转大写字母、大写字母转小写字母、数字字符转化为数字操作。
#include<bits/stdc++.h>
using namespace std;
int main(){
char c;
cin>>c; // 从标准输入读取一个字符
// 输出字符的ASCII码值
cout << "ASCII码值: " << (int)c << endl; // 将字符强制转换为int类型,得到ASCII码值
// 判断是否为数字字符,并转换为对应的数值
if('0'<=c && c<='9'){
int num=c-'0'; // 将数字字符转换为对应的整数值
cout << "数字值: " << num << endl;
}
// 判断是否为大写字母,并转换为对应的小写字母
if('A'<=c && c<='Z'){
char lower=c-'A'+'a'; // 大写字母转小写字母:加上'a'-'A'的差值(32)
cout << "小写形式: " << lower << endl;
}
// 判断是否为小写字母,并转换为对应的大写字母
if('a'<=c && c<='z'){
char upper=c-'a'+'A'; // 小写字母转大写字母:减去'a'-'A'的差值(32)
cout << "大写形式: " << upper << endl;
}
return 0;
}
import java.util.Scanner;
public class CharacterASCII {
public static void main(String[] args) {
// 从用户输入读取一个字符
Scanner scanner = new Scanner(System.in);
System.out.print("请输入一个字符: ");
char c = scanner.next().charAt(0);
scanner.close();
// 输出字符的ASCII码值
System.out.println("ASCII码值: " + (int)c); // 将字符强制转换为int类型,得到ASCII码值
// 判断是否为数字字符,并转换为对应的数值
if('0' <= c && c <= '9') {
int num = c - '0'; // 将数字字符转换为对应的整数值
System.out.println("数字值: " + num);
}
// 判断是否为大写字母,并转换为对应的小写字母
if('A' <= c && c <= 'Z') {
char lower = (char)(c - 'A' + 'a'); // 大写字母转小写字母:加上'a'-'A'的差值(32)
System.out.println("小写形式: " + lower);
// 也可以使用Java内置方法
System.out.println("使用Character.toLowerCase(): " + Character.toLowerCase(c));
}
// 判断是否为小写字母,并转换为对应的大写字母
if('a' <= c && c <= 'z') {
char upper = (char)(c - 'a' + 'A'); // 小写字母转大写字母:减去'a'-'A'的差值(32)
System.out.println("大写形式: " + upper);
// 也可以使用Java内置方法
System.out.println("使用Character.toUpperCase(): " + Character.toUpperCase(c));
}
// Java提供了更多字符判断的方法
System.out.println("是否为字母: " + Character.isLetter(c));
System.out.println("是否为数字: " + Character.isDigit(c));
System.out.println("是否为字母或数字: " + Character.isLetterOrDigit(c));
}
}
# Python中的字符就是长度为1的字符串
# 从用户输入读取一个字符
c = input("请输入一个字符: ")[0] # 获取输入的第一个字符
# 输出字符的ASCII码值
print(f"ASCII码值: {ord(c)}") # ord()函数返回字符的Unicode码点值(对于ASCII字符,与ASCII码值相同)
# 判断是否为数字字符,并转换为对应的数值
if '0' <= c <= '9':
num = int(c) # 在Python中可以直接使用int()将数字字符转换为整数
# 也可以使用ASCII码值的差值计算
num_ascii = ord(c) - ord('0')
print(f"数字值: {num}, 使用ASCII计算: {num_ascii}")
# 判断是否为大写字母,并转换为对应的小写字母
if 'A' <= c <= 'Z':
lower = chr(ord(c) - ord('A') + ord('a')) # 大写字母转小写字母
print(f"小写形式: {lower}")
# 也可以使用Python内置方法
print(f"使用lower()方法: {c.lower()}")
# 判断是否为小写字母,并转换为对应的大写字母
if 'a' <= c <= 'z':
upper = chr(ord(c) - ord('a') + ord('A')) # 小写字母转大写字母
print(f"大写形式: {upper}")
# 也可以使用Python内置方法
print(f"使用upper()方法: {c.upper()}")
# Python提供了更多字符判断的方法
print(f"是否为字母: {c.isalpha()}")
print(f"是否为数字: {c.isdigit()}")
print(f"是否为字母或数字: {c.isalnum()}")
字符串的声明与初始化
不同编程语言中,字符串的声明和初始化语法略有不同。
C++
在 C++ 中,字符串类型的变量的声明方法与其他类型变量一致,均为 变量类型 变量名 = 初始值;
。 对应到字符串类型,这个变量类型关键词为 string
。
string s1 ; // 声明一个空字符串
string s2 = "Hello, World!"; // 声明后初始化为一个特定字符串常量
需要特别注意的是,C++ 语法中为了区分字符类型常量和字符串类型常量,规定了:
- 字符串常量用双引号
"
括起来,例如"Hello, World!"
、"123"
等 - 字符常量用单引号
'
括起来,例如'A'
、'1'
、'+'
等
Java
Java中的字符串是使用String
类来表示的,它是一个不可变的字符序列。在 Java 中,字符串类型的变量的声明方法与其他类型变量一致,均为 变量类型 变量名 = 初始值;
。
// 声明一个空字符串
String s1 = "";
// 声明并初始化字符串
String s2 = "Hello, World!";
// 使用new关键字创建字符串对象
String s3 = new String("Hello, World!");
需要特别注意的是,在Java中,字符串常量用双引号"
括起来,而字符常量用单引号'
括起来,这一点与C++相同。需要注意的是,Java中的String是一个类,而不是基本数据类型。Java 的字符串是不可变的,这意味着一旦创建,就不能修改其内容。如果想要改变字符串中的的字符,你需要先将字符串转化为字符数组,然后修改字符数组内部的元素,最后再将这个字符数组转化为字符串。
Python
Python中的字符串是一种内置的数据类型,可以使用单引号'
、双引号"
或三引号'''
/"""
来表示。
# 声明一个空字符串
s1 = ""
# 使用单引号声明字符串
s2 = 'Hello, World!'
# 使用双引号声明字符串
s3 = "Hello, World!"
# 使用三引号声明多行字符串
s4 = """这是一个
多行字符串
示例"""
# 字符串重复
s5 = "Hello" * 3 # 结果为"HelloHelloHello"
# 从其他类型转换为字符串
s6 = str(123) # 将整数123转换为字符串"123"
需要特别注意的是,Python中没有单独的字符类型,一个字符就是长度为 1 的字符串。Python 的字符串是不可变的,这意味着一旦创建,就不能修改其内容。如果想要改变字符串中的的字符,你需要先将字符串转化为字符数组,然后修改字符数组内部的元素,最后再将这个字符数组转化为字符串。
字符串的访问
与数组类似,字符串中的字符也可以通过索引(下标)来访问,索引从 0 开始计数。同时,各个语言也都配备了对应的获取字符串长度的方法。
C++
在 C++ 中,获取字符串长度的语法是:
字符串变量名.size() //括号里面留空!
访问字符串第 个字符(从左往右数第一个字符是字符串的第 0 个字符)的语法是:
字符串变量名[索引] //索引即下标,即上面的 i
例如:
// C++ string类
string s = "Hello";
char first_char = s[0]; // 'H'
char last_char = s[s.size() - 1]; // 'o'
Java
在 Java 中,获取字符串长度的语法是:
字符串变量名.length() //括号里面留空!
访问字符串第 个字符(从左往右数第一个字符是字符串的第 0 个字符)的语法是:
字符串变量名.charAt(索引) //索引即下标,即上面的 i
例如:
// Java String类
String s = "Hello";
char first_char = s.charAt(0); // 'H'
char last_char = s.charAt(s.length() - 1); // 'o'
Python
在 Python 中,获取字符串长度的语法是:
len(字符串变量名) #使用内置函数len()
访问字符串第 个字符(从左往右数第一个字符是字符串的第
个字符)的语法是:
字符串变量名[索引] #索引即下标,即上面的 i
Python 还支持负索引,即从字符串末尾开始计数,-1 表示最后一个字符,-2 表示倒数第二个字符,以此类推。
例如:
# Python 字符串
s = "Hello"
first_char = s[0] # 'H'
last_char = s[len(s)-1] # 'o'
# 使用负索引
last_char_alt = s[-1] # 'o'
second_char = s[-4] # 'e'
字符串的遍历
遍历字符串是指按顺序访问字符串中的每个字符。对于字符串而言,我们可以先求出它最后一个元素的索引,然后使用 for 循环从小到大依次遍历所有可能的下标,进而依次遍历字符串中的各个元素。
C++
string str = "Hello";
for (int i = 0; i < str.size(); i++) {
cout << str[i] << " ";
}
// 输出: H e l l o
Java
String str = "Hello";
for (int i = 0; i < str.length(); i++) {
System.out.print(str.charAt(i) + " ");
}
// 输出: H e l l o
Python
str1 = "Hello"
# 直接遍历字符串
for char in str1:
print(char, end=" ")
# 输出: H e l l o
# 使用索引遍历
for i in range(len(str1)):
print(str1[i], end=" ")
# 输出: H e l l o
例题 1: YoungManDon'tSayFive
题意
给定一个由数字构成的字符串,将其中所有的数字 替换为字符
*
后输出。
思路分析
我们可以遍历整个字符串,如果遍历到字符 5
,就把字符串的这一位修改为 *
,修改后再输出即可。
代码实现
#include<bits/stdc++.h> // 包含C++标准库的头文件
using namespace std; // 使用标准命名空间
int main() {
string s; // 声明一个字符串变量s用于存储输入的数字字符串
cin >> s; // 从标准输入读取一个字符串
for (int i = 0;i < s.size(); i++) { // 遍历字符串的每个字符,s.size()返回字符串的长度
if (s[i] == '5')
s[i] = '*'; // 如果当前字符是'5',则将其替换为'*'
}
cout << s; // 输出修改后的字符串
return 0; // 程序正常结束
}
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in); // 创建Scanner对象用于读取输入
String s = scanner.next(); // 从标准输入读取一个字符串
scanner.close(); // 关闭Scanner对象
char[] chars = s.toCharArray(); // 将字符串转换为字符数组以便修改
for (int i = 0; i < chars.length; i++) { // 遍历字符数组的每个字符
if (chars[i] == '5')
chars[i] = '*'; // 如果当前字符是'5',则将其替换为'*'
}
String result = new String(chars); // 将修改后的字符数组转换回字符串
System.out.print(result); // 将修改后的字符数组转换回字符串并输出
}
}
# Python中字符串是不可变的,所以我们需要转换为列表进行修改,然后再转回字符串
s = input() # 从标准输入读取一个字符串
chars = list(s) # 将字符串转换为字符列表以便修改
for i in range(len(chars)): # 遍历字符列表的每个字符
if chars[i] == '5': # 如果当前字符是'5'
chars[i] = '*' # 则将其替换为'*'
for i in range(len(chars)): # 再次遍历字符列表
print(chars[i], end='') # 输出每个字符,之间以空字符隔开
字符串的常用操作
例题 1:字符串连接
将两个或多个字符串合并成一个新的字符串。
代码实现
// string 支持 + 直接连接两个字符串
string s1 = "Hello, ";
string s2 = "World!";
string result = s1 + s2; // "Hello, World!"
// 使用append方法(相比之下有点废柴)
s1.append(s2); // s1现在是"Hello, World!"
// 使用+运算符
String str1 = "Hello, ";
String str2 = "World!";
String result = str1 + str2; // "Hello, World!"
// 使用concat方法(相比之下有点废柴)
String result2 = str1.concat(str2); // "Hello, World!"
// 使用StringBuilder(推荐用于多次连接操作)
StringBuilder sb = new StringBuilder();
sb.append("Hello, ");
sb.append("World!");
String result3 = sb.toString(); // "Hello, World!"
# 使用+运算符
str1 = "Hello, "
str2 = "World!"
result = str1 + str2 # "Hello, World!"
# 使用join方法
result2 = "".join([str1, str2]) # "Hello, World!"
例题 2:子串提取
从字符串中提取一部分字符,形成新的字符串。
代码实现
string s = "Hello, World!";
string sub = s.substr(7, 5); // 从索引7开始,长度为5
// sub是"World"
String str = "Hello, World!";
// 使用substring方法
String sub1 = str.substring(7); // 从索引7到末尾: "World!"
String sub2 = str.substring(7, 12); // 从索引7到12(不含12): "World"
str1 = "Hello, World!"
# 使用切片操作
sub1 = str1[7:] # 从索引7到末尾: "World!"
sub2 = str1[7:12] # 从索引7到12(不含12): "World"
sub3 = str1[-6:-1] # 使用负索引: "World"
除此之外,字符串还有很多其他的操作,比如查找、替换、分割等等。这些操作在不同的语言中可能有不同的语法,但是基本的思路都是相似的。这些操作都可以通过上面的这些操作组合实现,你也可以自行查阅各个语言字符串的内置字符串功能库去背各个繁琐的内置函数,这里就不再赘述了。
课后习题
汗牛充栋,学海无涯。<br/> 内含算法知识点讲解,以及牛客题库精选例题。<br/> 学习算法,从牛栋开始。