字符串(String)
介绍
字符串是计算机科学中最常用的数据类型之一,它是由一系列字符组成的有限序列。在大多数编程语言中,字符串被作为基本数据类型或对象提供,用于表示文本。
从本质上讲,字符串可以看作是一个数组,但与普通数组不同,字符串有特殊的属性和操作方法,更适合处理文本数据。在Java等现代编程语言中,字符串是不可变的对象,这意味着一旦创建,其内容不能被修改。
核心特性
不可变性:在Java中,字符串对象一旦创建,其值不能被更改
字符序列:由多个字符按顺序排列组成
索引访问:可以通过索引访问单个字符,索引从0开始
字符串池:Java中常量字符串会被存储在字符串池中以节省内存
Unicode支持:可以包含任何Unicode字符,支持多语言文本
基本操作
代码实现
Java
▼Java复制代码// 创建字符串
String greeting = "你好,世界!";
String name = new String("Java编程");
// 字符串长度
int length = greeting.length(); // 6
// 连接字符串
String message = greeting + " 欢迎学习" + name;
String sameMassage = greeting.concat(" 欢迎学习").concat(name);
// 访问字符
char firstChar = greeting.charAt(0); // '你'
// 获取子字符串
String subStr = greeting.substring(0, 2); // "你好"
// 字符串比较
boolean isEqual = greeting.equals("你好,世界!"); // true
boolean ignoreCase = "Java".equalsIgnoreCase("java"); // true
// 查找
int index = message.indexOf("欢迎"); // 返回"欢迎"在字符串中首次出现的索引
boolean contains = message.contains("Java"); // true
// 替换
String newStr = greeting.replace('你', '我'); // "我好,世界!"
// 分割
String[] parts = "苹果,香蕉,橙子".split(","); // ["苹果", "香蕉", "橙子"]
// 转换大小写(仅适用于拉丁字母)
String upper = "hello".toUpperCase(); // "HELLO"
String lower = "HELLO".toLowerCase(); // "hello"
// 去除首尾空白
String trimmed = " hello ".trim(); // "hello"
JavaScript
▼Javascript复制代码// 创建字符串
let greeting = "你好,世界!";
let name = "JavaScript编程";
// 字符串长度
let length = greeting.length; // 6
// 连接字符串
let message = greeting + " 欢迎学习" + name;
let sameMassage = greeting.concat(" 欢迎学习", name);
// 访问字符
let firstChar = greeting[0]; // '你'
// 或者使用charAt
let firstCharAlt = greeting.charAt(0); // '你'
// 获取子字符串
let subStr = greeting.substring(0, 2); // "你好"
// 或者使用slice
let subStrAlt = greeting.slice(0, 2); // "你好"
// 字符串比较
let isEqual = greeting === "你好,世界!"; // true
let ignoreCase = "JavaScript".toLowerCase() === "javascript"; // true
// 查找
let index = message.indexOf("欢迎"); // 返回"欢迎"在字符串中首次出现的索引
let contains = message.includes("JavaScript"); // true
// 替换
let newStr = greeting.replace('你', '我'); // "我好,世界!"
// 全局替换
let globalReplace = "hello hello".replace(/hello/g, "hi"); // "hi hi"
// 分割
let parts = "苹果,香蕉,橙子".split(","); // ["苹果", "香蕉", "橙子"]
// 转换大小写
let upper = "hello".toUpperCase(); // "HELLO"
let lower = "HELLO".toLowerCase(); // "hello"
// 去除首尾空白
let trimmed = " hello ".trim(); // "hello"
// 模板字符串(ES6特性)
let template = `${greeting},欢迎学习${name}!`;
Python
▼Python复制代码# 创建字符串
greeting = "你好,世界!"
name = "Python编程"
# 字符串长度
length = len(greeting) # 6
# 连接字符串
message = greeting + " 欢迎学习" + name
# 或者使用join
message_alt = "".join([greeting, " 欢迎学习", name])
# 或者使用格式化
message_format = f"{greeting} 欢迎学习{name}"
# 访问字符
first_char = greeting[0] # '你'
# 获取子字符串
sub_str = greeting[0:2] # "你好"
# 字符串比较
is_equal = greeting == "你好,世界!" # True
ignore_case = "Python".lower() == "python" # True
# 查找
index = message.find("欢迎") # 返回"欢迎"在字符串中首次出现的索引
contains = "Python" in message # True
# 替换
new_str = greeting.replace('你', '我') # "我好,世界!"
# 限制替换次数
limited_replace = "hello hello".replace("hello", "hi", 1) # "hi hello"
# 分割
parts = "苹果,香蕉,橙子".split(",") # ["苹果", "香蕉", "橙子"]
# 转换大小写
upper = "hello".upper() # "HELLO"
lower = "HELLO".lower() # "hello"
# 去除首尾空白
trimmed = " hello ".strip() # "hello"
# 去除左侧空白
left_trimmed = " hello ".lstrip() # "hello "
# 去除右侧空白
right_trimmed = " hello ".rstrip() # " hello"
# 检查前缀后缀
starts_with = greeting.startswith("你好") # True
ends_with = greeting.endswith("!") # True
# 字符串格式化
formatted = "{},欢迎学习{}!".format(greeting, name)
Go
▼Go复制代码package main
import (
"fmt"
"strings"
"unicode/utf8"
)
func main() {
// 创建字符串
greeting := "你好,世界!"
name := "Go编程"
// 字符串长度(注意:对于多字节字符,len返回的是字节数,不是字符数)
byteLength := len(greeting) // 返回字节数
// 获取字符数(Unicode字符)
charLength := utf8.RuneCountInString(greeting) // 6
// 连接字符串
message := greeting + " 欢迎学习" + name
// 使用fmt.Sprintf连接
messageFmt := fmt.Sprintf("%s 欢迎学习%s", greeting, name)
// 使用strings.Join连接
messageJoin := strings.Join([]string{greeting, " 欢迎学习", name}, "")
// 访问字符(Go中字符串是只读字节序列,需要先转换为rune切片才能正确处理Unicode字符)
runes := []rune(greeting)
firstChar := string(runes[0]) // "你"
// 获取子字符串
// 对于ASCII字符可以直接切片,对于Unicode字符需要转换为rune切片
runeSlice := []rune(greeting)
subStr := string(runeSlice[0:2]) // "你好"
// 字符串比较
isEqual := greeting == "你好,世界!" // true
ignoreCase := strings.EqualFold("Go", "go") // true(不区分大小写比较)
// 查找
index := strings.Index(message, "欢迎") // 返回"欢迎"在字符串中首次出现的索引
contains := strings.Contains(message, "Go") // true
// 替换
newStr := strings.Replace(greeting, "你", "我", 1) // "我好,世界!"
// 替换所有
allReplaced := strings.ReplaceAll("hello hello", "hello", "hi") // "hi hi"
// 分割
parts := strings.Split("苹果,香蕉,橙子", ",") // ["苹果", "香蕉", "橙子"]
// 转换大小写
upper := strings.ToUpper("hello") // "HELLO"
lower := strings.ToLower("HELLO") // "hello"
// 去除首尾空白
trimmed := strings.TrimSpace(" hello ") // "hello"
// 前缀和后缀
hasPrefix := strings.HasPrefix(greeting, "你好") // true
hasSuffix := strings.HasSuffix(greeting, "!") // true
// 输出结果示例
fmt.Println(message, charLength, firstChar, subStr, isEqual, index, newStr, parts, trimmed)
}
C
▼C复制代码#include
#include
#include
#include
#include
int main() {
// 创建字符串(C中字符串是字符数组,以'�'结尾)
char greeting[] = "Hello, world!"; // ASCII字符
// 注意:C的原生char类型不支持Unicode,需要使用特定库如wchar_t或UTF-8编码
// 字符串长度
int length = strlen(greeting); // 13
// 连接字符串
char message[100]; // 预先分配足够空间
strcpy(message, greeting);
strcat(message, " Welcome to ");
strcat(message, "C programming");
// 另一种连接方式
char buffer[100];
sprintf(buffer, "%s Welcome to %s", greeting, "C programming");
// 访问字符
char firstChar = greeting[0]; // 'H'
// 获取子字符串(C中需要手动实现)
char subStr[10];
strncpy(subStr, greeting, 5);
subStr[5] = '�'; // 需要手动添加结束符
// 字符串比较
int isEqual = strcmp(greeting, "Hello, world!") == 0; // 1 (true)
// 不区分大小写比较(需要使用特定函数)
#ifdef _MSC_VER
int ignoreCase = _stricmp("C", "c") == 0; // Windows
#else
int ignoreCase = strcasecmp("C", "c") == 0; // POSIX
#endif
// 查找
char *found = strstr(message, "Welcome"); // 返回指向"Welcome"的指针或NULL
int index = found ? found - message : -1; // 计算索引位置
bool contains = found != NULL; // true
// 替换(C中需要手动实现)
char replaced[100];
strcpy(replaced, greeting);
// 查找并替换第一个'l'为'L'
char *pos = strchr(replaced, 'l');
if (pos != NULL) {
*pos = 'L';
}
// 分割字符串
char fruits[] = "apple,banana,orange";
char *token = strtok(fruits, ",");
while (token != NULL) {
printf("%s
", token);
token = strtok(NULL, ",");
}
// 转换大小写
char upper[100];
strcpy(upper, "hello");
for (int i = 0; upper[i]; i++) {
upper[i] = toupper(upper[i]);
}
char lower[100];
strcpy(lower, "HELLO");
for (int i = 0; lower[i]; i++) {
lower[i] = tolower(lower[i]);
}
// 去除首尾空白(C中需要手动实现)
char trimmed[] = " hello ";
char *trim_start = trimmed;
char *trim_end = trimmed + strlen(trimmed) - 1;
// 去除前导空格
while (*trim_start && isspace(*trim_start)) {
trim_start++;
}
// 去除尾部空格
while (trim_end > trim_start && isspace(*trim_end)) {
*trim_end-- = '�';
}
printf("Original: '%s', Trimmed: '%s'
", trimmed, trim_start);
return 0;
}
C++
▼C++复制代码#include
#include
#include
#include
#include
int main() {
// 创建字符串
std::string greeting = "你好,世界!";
std::string name = "C++编程";
// 字符串长度
size_t length = greeting.length(); // 返回Unicode码点数量,对于中文字符需要注意编码
// 连接字符串
std::string message = greeting + " 欢迎学习" + name;
// 使用append
std::string sameMessage = greeting;
sameMessage.append(" 欢迎学习").append(name);
// 使用ostringstream连接
std::ostringstream oss;
oss << greeting << " 欢迎学习" << name;
std::string ossMessage = oss.str();
// 访问字符
char firstChar = greeting[0]; // 注意:对于多字节字符可能不正确
// 获取子字符串
std::string subStr = greeting.substr(0, 2); // 注意:对于UTF-8编码的中文,偏移量是字节而非字符
// 字符串比较
bool isEqual = (greeting == "你好,世界!"); // true
// 不区分大小写比较(C++中需要手动实现或使用库)
auto compareIgnoreCase = [](const std::string& a, const std::string& b) {
if (a.size() != b.size()) return false;
return std::equal(a.begin(), a.end(), b.begin(),
[](char a, char b) {
return std::tolower(a) == std::tolower(b);
});
};
bool ignoreCase = compareIgnoreCase("C++", "c++"); // true
// 查找
size_t index = message.find("欢迎"); // 返回"欢迎"在字符串中首次出现的索引
bool contains = (message.find("C++") != std::string::npos); // true
// 替换
std::string newStr = greeting;
size_t pos = newStr.find("你");
if (pos != std::string::npos) {
newStr.replace(pos, 3, "我"); // "我好,世界!"(UTF-8中"你"占3字节)
}
// 全部替换
std::string text = "hello hello";
std::string pattern = "hello";
std::string replacement = "hi";
size_t start_pos = 0;
while ((start_pos = text.find(pattern, start_pos)) != std::string::npos) {
text.replace(start_pos, pattern.length(), replacement);
start_pos += replacement.length();
}
// 分割字符串
std::string fruitStr = "苹果,香蕉,橙子";
std::vector
std::string token;
std::istringstream tokenStream(fruitStr);
while (std::getline(tokenStream, token, ',')) {
fruits.push_back(token);
}
// 转换大小写
std::string upper = "hello";
std::transform(upper.begin(), upper.end(), upper.begin(),
[](unsigned char c){ return std::toupper(c); }); // "HELLO"
std::string lower = "HELLO";
std::transform(lower.begin(), lower.end(), lower.begin(),
[](unsigned char c){ return std::tolower(c); }); // "hello"
// 去除首尾空白
auto trim = [](std::string& s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return !std::isspace(ch);
}));
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return !std::isspace(ch);
}).base(), s.end());
return s;
};
std::string trimmed = " hello ";
trim(trimmed); // "hello"
// 输出示例
std::cout << "Message: " << message << std::endl;
std::cout << "First char: " << firstChar << std::endl;
std::cout << "Contains C++: " << std::boolalpha << contains << std::endl;
return 0;
}
优点
易用性:提供了丰富的API和操作方法,处理文本更简单
国际化支持:支持Unicode字符集,可以处理各种语言的文本
内存优化:字符串池机制减少内存使用
应用场景
文本处理:处理用户输入、配置文件、日志等
数据解析:解析JSON、XML、CSV等格式的数据
自然语言处理:文本分析、情感分析、机器翻译等
网络通信:HTTP请求参数、URL处理、网络协议等
用户界面:显示文本、多语言支持等
扩展
StringBuilder vs StringBuffer vs String
String:不可变,适合作为常量使用
StringBuilder:可变,非线程安全,适合在单线程环境中频繁修改字符串
StringBuffer:可变,线程安全,适合在多线程环境中使用,但性能略低于StringBuilder
字符串编码
字符串在内存中存储和在文件中保存时需要特定的编码方式,常见的编码包括ASCII、UTF-8、UTF-16等。
▼Java复制代码// 字符串与字节数组转换
String str = "你好,世界";
// 将字符串转换为UTF-8编码的字节数组
byte[] bytes = str.getBytes("UTF-8");
// 将字节数组转回字符串
String newStr = new String(bytes, "UTF-8");
// 检查编码是否支持
boolean supported = Charset.isSupported("UTF-8"); // true
常见编码比较
ASCII:只能表示128个字符,主要是英文字母、数字和符号
ISO-8859-1:扩展ASCII,可表示西欧语言字符
UTF-8:变长编码,英文占1字节,中文通常占3字节,兼容ASCII
UTF-16:Java内部使用的编码,所有字符占2或4字节
GBK/GB2312:中文编码标准,主要用于表示中文字符
测验
在Java中,String s1 = "hello"; 和 String s2 = new String("hello"); 创建的字符串有什么区别?
测验答案
s1使用字符串字面量创建,会首先在字符串常量池中查找"hello",如果存在则直接引用,不存在则在池中创建并引用。
s2使用构造函数创建,会在堆内存中创建一个新的String对象,即使常量池中已有相同内容的字符串。
所以s1 == s2返回false(比较引用),但s1.equals(s2)返回true(比较内容)。
相关LeetCode热门题目
字符串是编程中最常见的数据类型之一,是必须要掌握的内容。这里给大家推荐一些相关题目来练手:
14. 最长公共前缀 - 力扣(LeetCode) - 查找字符串数组的最长公共前缀
20. 有效的括号 - 判断字符串中的括号是否有效匹配
415. 字符串相加 - 将两个数字字符串相加