Day-7-字符串操作

Day 7: 字符串操作

🎯 学习目标

  • 掌握字符串的创建和基本操作
  • 学会使用字符串方法进行转换和查找
  • 理解字符串的不变性
  • 掌握模板字符串的使用
  • 学会处理常见的字符串操作场景

💡 核心概念

什么是字符串?

字符串是文本数据的序列,在 JavaScript 中用引号包围。

let str1 = "Hello";           // 双引号
let str2 = 'World';           // 单引号
let str3 = `Hello ${name}`;   // 模板字符串

字符串的特性

  • 不可变:字符串一旦创建不能修改
  • 索引访问:可以通过索引访问单个字符
  • 长度属性length 返回字符数量

📝 创建字符串

1. 字符串字面量

// 单引号和双引号等价
let str1 = "Hello";
let str2 = 'Hello';

// 模板字符串(ES6)
let name = "张三";
let str3 = `你好,${name}`;

2. 转义字符

let str1 = "他说:\"你好\"";
let str2 = 'It\'s a cat';
let str3 = "第一行\n第二行";  // 换行
let str4 = "路径:C:\\Users";   // 反斜杠
let str5 = "版权:\u00A9";      // Unicode

3. 长字符串

// 使用 + 连接
let longStr = "这是第一行" +
             "这是第二行" +
             "这是第三行";

// 使用模板字符串(推荐)
let longStr2 = `这是第一行
这是第二行
这是第三行`;

🔍 字符串属性和方法

基本属性

let str = "Hello";
console.log(str.length);      // 5
console.log(str[0]);           // "H"
console.log(str[str.length-1]); // "o"

大小写转换

let str = "Hello World";

console.log(str.toUpperCase());  // "HELLO WORLD"
console.log(str.toLowerCase());  // "hello world"

// 首字母大写
let capitalize = str[0].toUpperCase() + str.slice(1).toLowerCase();
console.log(capitalize);       // "Hello world"

查找和搜索

let str = "Hello World";

// indexOf() - 查找位置,不存在返回 -1
console.log(str.indexOf("World"));   // 6
console.log(str.indexOf("world"));   // -1(区分大小写)
console.log(str.indexOf("o"));       // 4(第一个出现的位置)

// lastIndexOf() - 最后一次出现的位置
console.log(str.lastIndexOf("o"));    // 7

// includes() - 是否包含
console.log(str.includes("World"));  // true
console.log(str.includes("world"));  // false

// startsWith() - 是否以...开头
console.log(str.startsWith("Hello")); // true
console.log(str.startsWith("World")); // false

// endsWith() - 是否以...结尾
console.log(str.endsWith("World"));   // true
console.log(str.endsWith("Hello"));  // false

// search() - 支持正则表达式
console.log(str.search(/World/i));   // 6(忽略大小写)

提取和截取

let str = "Hello World";

// charAt() - 获取指定位置的字符
console.log(str.charAt(0));          // "H"

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

// slice() - 提取子串(支持负数)
console.log(str.slice(0, 5));        // "Hello"
console.log(str.slice(6));           // "World"
console.log(str.slice(-5));          // "World"
console.log(str.slice(0, -6));       // "Hello"

// substring() - 提取子串(不支持负数)
console.log(str.substring(0, 5));    // "Hello"

// substr() - 已废弃,使用 slice 代替

替换和分割

let str = "Hello World";

// replace() - 替换(只替换第一个)
console.log(str.replace("World", "JavaScript")); // "Hello JavaScript"

// replaceAll() - 替换所有(ES2021)
console.log(str.replaceAll("l", "L"));          // "HeLLo WorLd"

// 或使用正则表达式全局替换
console.log(str.replace(/l/g, "L"));             // "HeLLo WorLd"

// split() - 分割字符串为数组
let str2 = "apple,banana,orange";
console.log(str2.split(","));  // ["apple", "banana", "orange"]

// 按空格分割
let str3 = "Hello World JavaScript";
console.log(str3.split(" "));   // ["Hello", "World", "JavaScript"]

// 按字符分割
console.log(str.split(""));     // ["H", "e", "l", "l", "o", " ", "W", "o", "r", "l", "d"]

去除空格

let str = "  Hello World  ";

// trim() - 去除首尾空格
console.log(str.trim());           // "Hello World"

// trimStart() / trimLeft() - 去除开头空格
console.log(str.trimStart());      // "Hello World  "

// trimEnd() / trimRight() - 去除尾部空格
console.log(str.trimEnd());        // "  Hello World"

// 使用正则去除所有空格
console.log(str.replace(/\s/g, "")); // "HelloWorld"

重复和填充

// repeat() - 重复字符串
console.log("Hi".repeat(3));        // "HiHiHi"

// padStart() - 开头填充
console.log("5".padStart(2, "0"));  // "05"
console.log("1".padStart(5, "0"));  // "00001"

// padEnd() - 尾部填充
console.log("5".padEnd(3, "."));    // "5.."

// 应用:格式化数字
let num = 42;
console.log(String(num).padStart(6, "0"));  // "000042"

比较字符串

let str1 = "apple";
let str2 = "banana";

// 按字典序比较
console.log(str1 < str2);   // true
console.log("a" < "b");     // true
console.log("A" < "a");     // true(大写字母的编码更小)

// localeCompare() - 本地化比较
console.log(str1.localeCompare(str2));  // -1(str1 在 str2 前面)
console.log("ä".localeCompare("z"));     // -1(考虑本地规则)

🎨 模板字符串

基本用法

let name = "张三";
let age = 25;

// 插值
let str = `姓名:${name},年龄:${age}`;
console.log(str);  // "姓名:张三,年龄:25"

// 表达式
let a = 10, b = 20;
console.log(`${a} + ${b} = ${a + b}`);  // "10 + 20 = 30"

// 调用函数
function greet(name) {
    return `Hello, ${name}!`;
}
console.log(`消息:${greet("张三")}`);  // "消息:Hello, 张三!"

多行字符串

// 模板字符串支持多行
let html = `
    <div>
        <h1>标题</h1>
        <p>段落</p>
    </div>
`;

// 传统方式需要用 +
let html2 = "<div>" +
            "<h1>标题</h1>" +
            "<p>段落</p>" +
            "</div>";

标签模板

function tag(strings, ...values) {
    console.log(strings);  // ["Hello ", "! ", ""]
    console.log(values);   // ["World", "JavaScript"]
    return "Processed";
}

let result = tag`Hello ${"World"}! ${"JavaScript"}`;
console.log(result);  // "Processed"

🎮 实战示例

示例1:用户名验证

function validateUsername(username) {
    // 去除空格
    username = username.trim();
    
    // 检查长度
    if (username.length < 3 || username.length > 20) {
        return {valid: false, message: "用户名长度必须在 3-20 个字符"};
    }
    
    // 检查是否只包含字母、数字、下划线
    if (!/^[a-zA-Z0-9_]+$/.test(username)) {
        return {valid: false, message: "用户名只能包含字母、数字、下划线"};
    }
    
    // 检查是否以字母开头
    if (!/^[a-zA-Z]/.test(username)) {
        return {valid: false, message: "用户名必须以字母开头"};
    }
    
    return {valid: true};
}

console.log(validateUsername("user123"));   // {valid: true}
console.log(validateUsername("123user"));   // {valid: false, message: "..."}

示例2:URL 构建

function buildURL(base, path, params) {
    // 去除 base 的结尾 /
    base = base.replace(/\/$/, "");
    
    // 去除 path 的开头 /
    path = path.replace(/^\//, "");
    
    // 构建 URL
    let url = `${base}/${path}`;
    
    // 添加查询参数
    if (params) {
        let query = Object.keys(params)
            .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)
            .join("&");
        url += `?${query}`;
    }
    
    return url;
}

console.log(buildURL("https://api.example.com", "users", {page: 1, limit: 10}));
// "https://api.example.com/users?page=1&limit=10"

示例3:文件路径处理

function getFileName(path) {
    // 获取最后一个 / 之后的内容
    return path.slice(path.lastIndexOf("/") + 1);
}

function getFileExtension(filename) {
    // 获取最后一个 . 之后的内容
    return filename.slice(filename.lastIndexOf(".") + 1);
}

function getFilePath(filename) {
    // 获取最后一个 / 之前的内容
    return filename.slice(0, filename.lastIndexOf("/"));
}

let path = "/home/user/documents/file.txt";
console.log(getFileName(path));        // "file.txt"
console.log(getFileExtension(path));   // "txt"
console.log(getFilePath(path));       // "/home/user/documents"

示例4:文本格式化

function formatText(text) {
    // 去除首尾空格
    text = text.trim();
    
    // 将多个连续空格替换为单个空格
    text = text.replace(/\s+/g, " ");
    
    // 首字母大写
    text = text.charAt(0).toUpperCase() + text.slice(1).toLowerCase();
    
    return text;
}

console.log(formatText("  hello    world  "));  // "Hello world"

示例5:生成随机字符串

function generateRandomString(length, charset) {
    let result = "";
    charset = charset || "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    
    for (let i = 0; i < length; i++) {
        result += charset.charAt(Math.floor(Math.random() * charset.length));
    }
    
    return result;
}

console.log(generateRandomString(10));  // "aB3xY9pQ2m"
console.log(generateRandomString(8, "ABCDEF123456"));  // "3D1FA6C2"

示例6:驼峰命名转换

// 驼峰转短横线
function camelToKebab(str) {
    return str.replace(/([A-Z])/g, "-$1").toLowerCase();
}

// 短横线转驼峰
function kebabToCamel(str) {
    return str.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
}

// 驼峰转蛇形
function camelToSnake(str) {
    return str.replace(/([A-Z])/g, "_$1").toLowerCase();
}

console.log(camelToKebab("backgroundColor"));  // "background-color"
console.log(kebabToCamel("background-color")); // "backgroundColor"
console.log(camelToSnake("backgroundColor"));   // "background_color"

✍️ 练习任务

练习1:统计字符出现次数

function countCharacters(str) {
    let count = {};
    for (let char of str) {
        count[char] = (count[char] || 0) + 1;
    }
    return count;
}

console.log(countCharacters("hello"));
// {h: 1, e: 1, l: 2, o: 1}

练习2:反转字符串

function reverseString(str) {
    return str.split("").reverse().join("");
}

console.log(reverseString("Hello"));  // "olleH"

练习3:检查回文

function isPalindrome(str) {
    // 去除空格和标点,转小写
    str = str.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
    // 反转比较
    return str === str.split("").reverse().join("");
}

console.log(isPalindrome("A man, a plan, a canal: Panama"));  // true

🎓 今日挑战

项目:Markdown 解析器

实现简单的 Markdown 转 HTML:

function parseMarkdown(markdown) {
    let html = markdown;
    
    # 标题
    html = html.replace(/^# (.*$)/gim, "<h1>$1</h1>");
    html = html.replace(/^## (.*$)/gim, "<h2>$1</h2>");
    html = html.replace(/^### (.*$)/gim, "<h3>$1</h3>");
    
    # 粗体和斜体
    html = html.replace(/\*\*(.*?)\*\*/gim, "<b>$1</b>");
    html = html.replace(/\*(.*?)\*/gim, "<i>$1</i>");
    
    # 代码
    html = html.replace(/`([^`]+)`/gim, "<code>$1</code>");
    
    # 链接
    html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/gim, "<a href='$2'>$1</a>");
    
    return html;
}

console.log(parseMarkdown("# Hello\n这是 **粗体** 和 *斜体*"));

💡 最佳实践

1. 优先使用模板字符串

// ✅ 好
let str = `Hello ${name}`;

// ❌ 差
let str = "Hello " + name;

2. 避免在循环中拼接字符串

// ❌ 不好(每次创建新字符串)
let str = "";
for (let i = 0; i < 1000; i++) {
    str += i;
}

// ✅ 好用数组
let parts = [];
for (let i = 0; i < 1000; i++) {
    parts.push(i);
}
let str = parts.join("");

3. 使用正则表达式处理复杂模式

// 验证邮箱
function isValidEmail(email) {
    return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

学习时间: 2026-03-08 03:05
难度: ⭐⭐⭐☆☆
预计用时: 2-3 小时
关键词: 字符串, 模板字符串, 正则表达式
相关标签: #05-字符串