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 解析等。

相关推荐
陈随易3 小时前
有生之年系列,Nodejs进程管理pm2 v7.0发布
前端·后端·程序员
陈随易4 小时前
AI时代,你还在坚持手搓文章吗
前端·后端·程序员
大鱼七成饱5 小时前
VMware NAT模式下固定内网IP(附详细图文)
后端
IT_陈寒7 小时前
Vue的这个响应式陷阱,我debug了一整天才爬出来
前端·人工智能·后端
兔子零10248 小时前
手把手教你在 Claude Code 中接入 DeepSeek-V4
后端
phenhorlin8 小时前
我做了个工具,让切换 Homebrew 镜像像切 npm 源一样简单
后端·shell
6958 小时前
两周浅学 RAG
后端
AI人工智能+电脑小能手9 小时前
【大白话说Java面试题】【Java基础篇】第24题:Java面向对象有哪些特征
java·开发语言·后端·面试
AI人工智能+电脑小能手10 小时前
【大白话说Java面试题】【Java基础篇】第25题:JDK1.8的新特性有哪些
java·开发语言·后端·面试
fliter10 小时前
Wrangler:Cloudflare 给 Rust + WASM 开发者造的那把锤子
后端