C++ 中 rfind 方法详解

rfind 是 C++ 字符串类 std::stringstd::wstring 的成员函数,用于从字符串的末尾向前搜索指定的子字符串或字符。

函数原型

cpp 复制代码
// 搜索整个字符串
size_type rfind(const basic_string& str, size_type pos = npos) const noexcept;
size_type rfind(const CharT* s, size_type pos = npos) const;
size_type rfind(CharT ch, size_type pos = npos) const noexcept;

// C++17 新增:带长度的版本
size_type rfind(const CharT* s, size_type pos, size_type count) const;

参数说明

  • str / s / ch:要搜索的子字符串或字符
  • pos:开始搜索的位置(从该位置向前搜索)
  • count:要搜索的字符数(仅用于指针版本)

返回值

  • 如果找到,返回匹配子串的起始位置(从 0 开始)
  • 如果未找到,返回 std::string::npos

源码解析

以下是 rfind 的简化实现原理:

cpp 复制代码
#include <iostream>
#include <string>
#include <cstring>

// 简化的 rfind 实现原理
size_t simplified_rfind(const std::string& str, const std::string& pattern, size_t pos = std::string::npos) {
    // 如果 pos 超过字符串长度,调整到字符串末尾
    if (pos >= str.length()) {
        pos = str.length() - 1;
    }
    
    // 如果模式串为空,返回 pos(标准行为)
    if (pattern.empty()) {
        return (pos < str.length()) ? pos : str.length();
    }
    
    // 如果模式串比原字符串长,肯定找不到
    if (pattern.length() > str.length()) {
        return std::string::npos;
    }
    
    // 从 pos 开始向前搜索
    for (size_t i = pos; i >= pattern.length() - 1; --i) {
        bool found = true;
        
        // 检查当前位置是否匹配模式串
        for (size_t j = 0; j < pattern.length(); ++j) {
            if (str[i - pattern.length() + 1 + j] != pattern[j]) {
                found = false;
                break;
            }
        }
        
        if (found) {
            return i - pattern.length() + 1;
        }
        
        // 处理无符号整数的下溢
        if (i == 0) break;
    }
    
    return std::string::npos;
}

使用示例

cpp 复制代码
#include <iostream>
#include <string>

int main() {
    std::string text = "Hello, World! Hello, C++!";
    
    // 1. 搜索子字符串
    size_t pos1 = text.rfind("Hello");
    std::cout << "Last 'Hello' at position: " << pos1 << std::endl; // 输出 14
    
    // 2. 搜索字符
    size_t pos2 = text.rfind('o');
    std::cout << "Last 'o' at position: " << pos2 << std::endl; // 输出 19
    
    // 3. 从指定位置向前搜索
    size_t pos3 = text.rfind("Hello", 10);
    std::cout << "Last 'Hello' before position 10: " << pos3 << std::endl; // 输出 0
    
    // 4. 搜索不存在的字符串
    size_t pos4 = text.rfind("Python");
    if (pos4 == std::string::npos) {
        std::cout << "'Python' not found" << std::endl;
    }
    
    // 5. 使用指针和长度
    const char* search_str = "Hello";
    size_t pos5 = text.rfind(search_str, text.length(), 3); // 只搜索前3个字符 "Hel"
    std::cout << "Last 'Hel' at position: " << pos5 << std::endl;
    
    return 0;
}

实际应用场景

cpp 复制代码
#include <iostream>
#include <string>

// 提取文件扩展名
std::string getFileExtension(const std::string& filename) {
    size_t dotPos = filename.rfind('.');
    if (dotPos != std::string::npos && dotPos < filename.length() - 1) {
        return filename.substr(dotPos + 1);
    }
    return "";
}

// 提取目录路径
std::string getDirectory(const std::string& path) {
    size_t slashPos = path.rfind('/');
    if (slashPos != std::string::npos) {
        return path.substr(0, slashPos + 1);
    }
    return "";
}

// 查找最后一个单词
std::string getLastWord(const std::string& sentence) {
    size_t lastSpace = sentence.rfind(' ');
    if (lastSpace != std::string::npos) {
        return sentence.substr(lastSpace + 1);
    }
    return sentence; // 没有空格,返回整个字符串
}

int main() {
    std::string filename = "document.backup.txt";
    std::string path = "/home/user/documents/file.txt";
    std::string sentence = "The quick brown fox";
    
    std::cout << "File extension: " << getFileExtension(filename) << std::endl;
    std::cout << "Directory: " << getDirectory(path) << std::endl;
    std::cout << "Last word: " << getLastWord(sentence) << std::endl;
    
    return 0;
}

性能特点

  • 时间复杂度:最坏情况 O(n×m),其中 n 是搜索范围,m 是模式串长度
  • 空间复杂度:O(1)
  • 适用场景:适合在长字符串中查找较短的模式串

注意事项

  1. rfind 从后向前搜索,但返回的位置是从字符串开头计算的
  2. 如果 pos 参数为 npos,则从字符串末尾开始搜索
  3. 空字符串的搜索总是会成功(返回 pos 或字符串长度)
  4. 注意处理 npos 的返回值

rfind 是字符串处理中非常有用的工具,特别适合需要从后向前搜索的场景,如文件路径处理、URL 解析等。

相关推荐
AAA修煤气灶刘哥5 小时前
服务器指标多到“洪水泛滥”?试试InfluxDB?
数据库·后端·面试
uzong5 小时前
技术面试,时间不足15分钟,面试官就挂掉了电话,原因竟然是……
后端·面试
Roye_ack5 小时前
【项目实战 Day12】springboot + vue 苍穹外卖系统(Apache POI + 工作台模块 + Excel表格导出 完结)
java·spring boot·后端·excel·苍穹外卖
kobe_OKOK_6 小时前
Django ORM 字段查询表达式(Field lookup expressions)
后端·python·django
qq_5470261796 小时前
SpringBoot+Redis实现电商秒杀方案
spring boot·redis·后端
Code blocks6 小时前
SpringBoot自定义请求前缀
java·spring boot·后端
爱学大树锯6 小时前
【Spring Boot JAR 解压修改配置后重新打包全流程(避坑指南)】
spring boot·后端·jar
kobe_OKOK_6 小时前
Django ORM 无法通过 `ForeignKey` 自动关联,而是需要 **根据父模型中的某个字段(比如 ID)去查询子模型**。
后端·python·django