字符串处理

全面掌握JavaScript字符串的创建、操作、常用方法和高级技巧

字符串概述

字符串是表示文本数据的基本数据类型,在JavaScript中:

  • 字符串是不可变的(immutable)
  • 可以使用单引号、双引号或反引号创建
  • 支持Unicode字符集
  • 提供丰富的内置方法
  • 支持模板字符串(ES6)
  • 可以使用正则表达式进行复杂匹配

字符串创建

有多种方式可以创建字符串:

字符串创建
// 字符串字面量
let str1 = '单引号字符串';
let str2 = "双引号字符串";
let str3 = `模板字符串`;

// 字符串构造函数
let str4 = new String("字符串对象");

// 空字符串
let empty = "";

console.log(typeof str1);  // "string"
console.log(typeof str4);  // "object"

// 建议使用字面量而不是构造函数

字符串基本操作

访问字符

访问字符
let str = "Hello, World!";

// 使用索引访问字符
console.log(str[0]);   // "H"
console.log(str[7]);   // "W"

// 使用 charAt() 方法
console.log(str.charAt(0));  // "H"
console.log(str.charAt(7));  // "W"

// 访问不存在的索引
console.log(str[100]);        // undefined
console.log(str.charAt(100));  // "" (空字符串)

// 获取字符编码
console.log(str.charCodeAt(0));  // 72 (H的Unicode编码)

字符串长度和遍历

字符串长度和遍历
let str = "JavaScript";

// 获取字符串长度
console.log(str.length);  // 10

// 使用 for 循环遍历
for (let i = 0; i < str.length; i++) {
    console.log(str[i]);
}

// 使用 for...of 循环遍历
for (let char of str) {
    console.log(char);
}

// 转换为数组再遍历
let chars = str.split("");
chars.forEach(char => console.log(char));

字符串方法 - 搜索和检查

方法 描述 示例 返回值
indexOf() 查找子串位置 "hello".indexOf("l") 2
lastIndexOf() 从后向前查找 "hello".lastIndexOf("l") 3
includes() 检查是否包含 "hello".includes("ell") true
startsWith() 检查是否以某字符串开头 "hello".startsWith("he") true
endsWith() 检查是否以某字符串结尾 "hello".endsWith("lo") true
search() 使用正则表达式搜索 "hello".search(/[aeiou]/) 1
搜索和检查示例
let text = "Hello, JavaScript World!";

// indexOf() 和 lastIndexOf()
console.log(text.indexOf("Java"));        // 7
console.log(text.lastIndexOf("o"));        // 19
console.log(text.indexOf("Python"));      // -1 (未找到)

// includes(), startsWith(), endsWith()
console.log(text.includes("JavaScript"));  // true
console.log(text.startsWith("Hello"));       // true
console.log(text.endsWith("World!"));       // true

// 可以指定搜索的起始位置
console.log(text.includes("Java", 10));  // false (从位置10开始搜索)

// search() - 使用正则表达式
console.log(text.search("Java"));           // 7
console.log(text.search(/[A-Z]/));          // 0 (第一个大写字母的位置)

字符串方法 - 提取和分割

方法 描述 示例 返回值
slice() 提取子字符串 "hello".slice(1, 4) "ell"
substring() 提取子字符串 "hello".substring(1, 4) "ell"
substr() 提取子字符串 "hello".substr(1, 3) "ell"
split() 分割字符串为数组 "a,b,c".split(",") ["a", "b", "c"]
提取和分割示例
let text = "Hello, JavaScript!";

// slice(start, end) - 提取从start到end(不包括end)的子串
console.log(text.slice(7));         // "JavaScript!" (从位置7到末尾)
console.log(text.slice(7, 17));     // "JavaScript" (从位置7到17)
console.log(text.slice(-6));        // "Script!" (最后6个字符)
console.log(text.slice(-10, -1));  // "JavaScript"

// substring(start, end) - 类似slice,但不支持负数
console.log(text.substring(7));      // "JavaScript!"
console.log(text.substring(7, 17));  // "JavaScript"

// substr(start, length) - 从start开始提取length个字符
console.log(text.substr(7));         // "JavaScript!"
console.log(text.substr(7, 10));     // "JavaScript"

// split(separator, limit) - 分割字符串
let csv = "apple,banana,orange,grape";
console.log(csv.split(","));          // ["apple", "banana", "orange", "grape"]
console.log(csv.split(",", 2));       // ["apple", "banana"] (限制返回2个元素)

// 使用正则表达式分割
let sentence = "Hello World! How are you?";
console.log(sentence.split(/\s+/));  // ["Hello", "World!", "How", "are", "you?"]
注意: substr()方法已不被推荐使用,建议使用slice()substring()

字符串方法 - 修改和转换

方法 描述 示例 返回值
toUpperCase() 转换为大写 "hello".toUpperCase() "HELLO"
toLowerCase() 转换为小写 "HELLO".toLowerCase() "hello"
trim() 去除两端空格 " hello ".trim() "hello"
replace() 替换子字符串 "hello".replace("l", "x") "hexlo"
concat() 连接字符串 "hello".concat(" ", "world") "hello world"
repeat() 重复字符串 "hi".repeat(3) "hihihi"
修改和转换示例
// 大小写转换
let text = "Hello World";
console.log(text.toUpperCase());  // "HELLO WORLD"
console.log(text.toLowerCase());  // "hello world"

// 去除空格
let spaced = "   Hello World!   ";
console.log(spaced.trim());        // "Hello World!"
console.log(spaced.trimStart());   // "Hello World!   "
console.log(spaced.trimEnd());     // "   Hello World!"

// 替换内容
let message = "I like cats. Cats are nice.";
console.log(message.replace("cats", "dogs"));        // "I like dogs. Cats are nice."
console.log(message.replace(/cats/gi, "dogs"));  // "I like dogs. Dogs are nice."

// 连接字符串
let hello = "Hello";
let world = "World";
console.log(hello.concat(", ", world, "!"));  // "Hello, World!"

// 重复字符串
console.log("Ha".repeat(3));  // "HaHaHa"
console.log("*".repeat(10));  // "**********"

// 字符串填充
let num = "5";
console.log(num.padStart(3, "0"));  // "005"
console.log(num.padEnd(3, "0"));    // "500"

模板字符串 (ES6)

模板字符串使用反引号(`)创建,支持多行文本和表达式插值:

模板字符串
// 基本模板字符串
let name = "张三";
let age = 25;
let greeting = `Hello, ${name}! You are ${age} years old.`;
console.log(greeting);  // "Hello, 张三! You are 25 years old."

// 多行字符串
let multiLine = `这是第一行
这是第二行
这是第三行`;
console.log(multiLine);

// 表达式计算
let a = 5, b = 10;
console.log(`${a} + ${b} = ${a + b}`);  // "5 + 10 = 15"

// 函数调用
function double(x) {
    return x * 2;
}
console.log(`双倍 ${a}${double(a)}`);  // "双倍 5 是 10"

// 标签模板
function highlight(strings, ...values) {
    let result = "";
    strings.forEach((string, i) => {
        result += string;
        if (i < values.length) {
            result += `<mark>${values[i]}</mark>`;
        }
    });
    return result;
}

let highlighted = highlight`Hello ${name}, you are ${age} years old.`;
console.log(highlighted);  // "Hello <mark>张三</mark>, you are <mark>25</mark> years old."

字符串和Unicode

JavaScript字符串使用UTF-16编码:

Unicode相关操作
// 基本Unicode字符
let heart = "❤";
let chinese = "中文";
let emoji = "😀";

console.log(heart.length);      // 1
console.log(chinese.length);    // 2
console.log(emoji.length);      // 2 (某些emoji是代理对)

// 使用Unicode转义序列
let unicodeStr = "\u0048\u0065\u006C\u006C\u006F";  // "Hello"
let emojiStr = "\u{1F600}";  // "😀"

// 码点相关方法
let str = "😀";
console.log(str.codePointAt(0));        // 128512
console.log(String.fromCodePoint(128512));  // "😀"

// 正确处理Unicode的遍历
let specialStr = "❤😀中文";

// 错误的方式 (可能拆分代理对)
for (let i = 0; i < specialStr.length; i++) {
    console.log(specialStr[i]);
}

// 正确的方式
for (let char of specialStr) {
    console.log(char);
}

// 使用 Array.from()
let chars = Array.from(specialStr);
console.log(chars);  // ["❤", "😀", "中", "文"]

字符串编码和解码

处理URL编码、Base64编码等:

编码和解码操作
// URL编码和解码
let url = "https://example.com/search?q=JavaScript 教程";
let encodedURL = encodeURI(url);
let decodedURL = decodeURI(encodedURL);

console.log(encodedURL);  // "https://example.com/search?q=JavaScript%20%E6%95%99%E7%A8%8B"
console.log(decodedURL);  // 原始URL

// 组件编码(更严格)
let component = "JavaScript 教程";
console.log(encodeURIComponent(component));  // "JavaScript%20%E6%95%99%E7%A8%8B"

// Base64编码和解码
let text = "Hello, World!";
let base64 = btoa(text);        // 编码为Base64
let decoded = atob(base64);     // 解码Base64

console.log(base64);    // "SGVsbG8sIFdvcmxkIQ=="
console.log(decoded);   // "Hello, World!"

// 处理Unicode的Base64编码
function unicodeBtoa(str) {
    return btoa(unescape(encodeURIComponent(str)));
}

function unicodeAtob(str) {
    return decodeURIComponent(escape(atob(str)));
}

let chineseText = "你好,世界!";
let chineseBase64 = unicodeBtoa(chineseText);
console.log(chineseBase64);  // "5L2g5aW977yM5LiW55WM77yB"
console.log(unicodeAtob(chineseBase64));  // "你好,世界!"

字符串国际化

使用Intl API进行字符串本地化:

国际化字符串处理
// 字符串排序和比较
let words = ["ä", "z", "a"];

// 默认排序(基于Unicode码点)
console.log(words.sort());  // ["a", "z", "ä"]

// 使用本地化排序
let germanSorter = new Intl.Collator('de');
console.log(words.sort(germanSorter.compare));  // ["a", "ä", "z"]

// 字符串格式化
let date = new Date();
let formatter = new Intl.DateTimeFormat('zh-CN');
console.log(formatter.format(date));  // 本地化日期格式

// 数字格式化
let numberFormatter = new Intl.NumberFormat('zh-CN');
console.log(numberFormatter.format(1234567.89));  // "1,234,567.89"

// 相对时间格式化
let rtf = new Intl.RelativeTimeFormat('zh-CN');
console.log(rtf.format(-1, 'day'));   // "1天前"
console.log(rtf.format(2, 'week'));   // "2周后"

正则表达式与字符串

使用正则表达式进行复杂的字符串匹配和处理:

正则表达式应用
// 基本匹配
let text = "Hello, my email is example@email.com";
let emailRegex = /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/;
let match = text.match(emailRegex);
console.log(match);  // ["example@email.com"]

// 全局匹配
let words = "apple banana apple cherry";
let appleRegex = /apple/g;
let matches = words.match(appleRegex);
console.log(matches);  // ["apple", "apple"]

// 替换操作
let phone = "Phone: 123-456-7890";
let formatted = phone.replace(/(\d{3})-(\d{3})-(\d{4})/, '($1) $2-$3');
console.log(formatted);  // "Phone: (123) 456-7890"

// 验证格式
function isValidEmail(email) {
    let emailRegex = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}$/;
    return emailRegex.test(email);
}

console.log(isValidEmail("test@example.com"));  // true
console.log(isValidEmail("invalid-email"));      // false

// 提取信息
function extractDomain(email) {
    let domainRegex = /@([A-Za-z0-9.-]+\.[A-Z|a-z]{2,})/;
    let match = email.match(domainRegex);
    return match ? match[1] : null;
}

console.log(extractDomain("user@example.com"));  // "example.com"

字符串性能优化

处理大量字符串时的性能优化技巧:

性能优化技巧
// 使用数组连接大量字符串
function buildStringEfficiently(strings) {
    let result = [];
    for (let i = 0; i < strings.length; i++) {
        result.push(strings[i]);
    }
    return result.join('');
}

// 避免在循环中使用字符串连接
// 不好的做法
function buildStringInefficient(strings) {
    let result = '';
    for (let i = 0; i < strings.length; i++) {
        result += strings[i];  // 每次都会创建新字符串
    }
    return result;
}

// 使用模板字符串的性能考虑
let name = "John";
let age = 30;

// 性能较好(字面量模板)
let message1 = `Hello, ${name}! You are ${age} years old.`;

// 性能较差(动态模板)
function createMessage(name, age) {
    return `Hello, ${name}! You are ${age} years old.`;
}

// 使用字符串缓存
let stringCache = new Map();
function getCachedString(key, generator) {
    if (!stringCache.has(key)) {
        stringCache.set(key, generator());
    }
    return stringCache.get(key);
}

实践练习

👆 请点击上方按钮进行演示操作

选择不同的演示按钮来探索JavaScript字符串的各种功能和用法

最佳实践

  • 优先使用模板字符串而不是字符串连接
  • 使用includes()而不是indexOf() !== -1检查包含
  • 处理Unicode字符时使用for...ofArray.from()
  • 使用trim()清理用户输入
  • 对于复杂的字符串操作,考虑使用正则表达式
  • 避免使用String构造函数,使用字面量
  • 处理大量字符串时使用数组连接而不是直接连接
  • 使用IntlAPI进行本地化字符串处理

下一步学习

掌握了字符串后,接下来可以学习: