C++ string内的搜索

本文介绍了使用C++标准库中的字符串方法进行数据处理的技术,包括提取数字与字母、筛选特定字符及日期格式转换等实用案例。

用find_first_of和find_first_not_of找出string中的数字和字母字符

#include"stdafx.h"
#include<iostream>
#include<string>
//#include "ProgramRunClock.h"
//#include<vector>
//#include<list>
//#include<time.h>
using namespace std;

int main(int argc, char **argv) {
    string base = "ab2c3d7R4E6";
    string digits, letters;
    size_t index = 0;
    while (true)
    {
        index = base.find_first_of("0123456789", index);
        if (index == base.npos)break;
        digits.push_back(base[index]);
        index++;
    }
    index = 0;
    while (true)
    {
        index = base.find_first_not_of("0123456789", index);
        if (index == base.npos)break;
        letters.push_back(base[index]);
        index++;
    }
    cout << digits << endl << letters << endl;
    return 0;
}

读取字符串(单词)文件筛选出不含特定字母的单词

#include"stdafx.h"
#include<iostream>
#include<string>
#include<fstream>
//#include "ProgramRunClock.h"
#include<vector>
//#include<list>
//#include<time.h>
using namespace std;

int main(int argc, char **argv) {
    ifstream wordgetin(argv[1]);
    string temp;
    vector<string> words, eligibleWords; 
    string comparewith{ "bdfgjpqy" };
    while (wordgetin >> temp)words.emplace_back(temp);
    for (auto word : words)
    {
        if (word.find_first_of(comparewith) == word.npos)eligibleWords.emplace_back(word);
    }
    for (auto word : eligibleWords)
    {
        cout << word << endl;
    }
    return 0;
}

在stringvector里计算包含数字的字符串元素转化后的和

#include"stdafx.h"
#include<iostream>
#include<string>
#include<fstream>
//#include "ProgramRunClock.h"
#include<vector>
//#include<list>
//#include<time.h>
using namespace std;
float VecTransformSum(vector<string> svec)
{
    float sum = 0;
    string buffer;
    for (auto itr = svec.begin(); itr != svec.end(); itr++)
    {
        buffer = *itr;
        buffer = buffer.substr(buffer.find_first_of("+-.0123456789"));
        sum += stof(buffer);
    }
    return sum;
}
int main(int argc, char **argv) {
    vector<string> ivec{"hda1.2","bdax2.4","scaf3.1","lwefeafewagfes4.6","yafafaq5.6"};
    cout << VecTransformSum(ivec) << endl;
    return 0;
}

一个用string内部函数,将不同类型的日期转化为标准格式的类

#include"stdafx.h"
#include<iostream>
#include<string>
#include<fstream>
#include<sstream>
//#include "ProgramRunClock.h"
#include<vector>
//#include<list>
//#include<time.h>
using namespace std;
class YearMonthDay
{
public:
    YearMonthDay() = default;
    YearMonthDay(const string &base);
    const string getdatestr()
    {
        stringstream buffer;
        string temp, result;
        buffer << year; buffer >> temp; result.append(temp + "年"); buffer.clear();
        buffer << month; buffer >> temp; result.append(temp + "月"); buffer.clear();
        buffer << day; buffer >> temp; result.append(temp+"日");
        return result;
    }
private:
    unsigned year = 1970;
    unsigned month = 1;
    unsigned day = 1;
};
YearMonthDay::YearMonthDay(const string &base)
{//在这些vector里找月数关键词
    string str_year, str_month, str_day;
    bool english_month = false;
    vector<string> uppercase{ "January","February" ,"March", "April", "May" ,"June" ,"July", "August" ,"September" ,"October" ,"November" ,"December"};
    vector<string> lowercase{ "january","february" ,"march", "april", "may" ,"june" ,"july", "august" ,"september" ,"october" ,"november" ,"december" };
    vector<string> uppercase_abbreviation{ "Jan","Feb" ,"Mar", "Apr", "May" ,"Jun" ,"Jul", "Aug" ,"Sep" ,"Oct" ,"Nov" ,"Dec" };
    vector<string> lowercase_abbreviation{ "jan","feb" ,"mar", "apr", "may" ,"jun" ,"jul", "aug" ,"sep" ,"oct" ,"nov" ,"dec" };
    for (size_t index = 0; index != 12; index++)
    {//根据下标用find找4个vector中对应的作为base子字符串的元素
        size_t search_one = base.find(uppercase[index]), 
            search_two = base.find(lowercase[index]),
            search_three = base.find(uppercase_abbreviation[index]),
            search_four = base.find(lowercase_abbreviation[index]);//在四个vector里找到的子串的首字符位置
        if (search_one!=base.npos)
        {
            month = index + 1;
            str_month = uppercase[index];
            english_month = true;
            break;
        }
        if (search_two != base.npos)
        {
            month = index + 1;//如果能找到就根据下标给month赋值
            str_month = lowercase[index];
            english_month = true;
            break;
        }
        if (search_three != base.npos)
        {
            month = index + 1;
            str_month = uppercase_abbreviation[index];
            english_month = true;
            break;
        }
        if (search_four != base.npos)
        {
            month = index + 1;
            str_month = lowercase_abbreviation[index];
            english_month = true;
            break;
        }
    }

    vector<string> years_compare;
    stringstream buffer;
    string temp;
    for (size_t y = 1900; y <= 2100; y++)
    {
        buffer << y;
        buffer >> temp;
        years_compare.emplace_back(temp);
        buffer.clear();
    }//年份vector一共200年 1900-2100
    for (size_t index = 0; index <= 200; index++)
    {
        size_t search = base.find(years_compare[index]);
        if (search != base.npos)
        {
            year = 1900 + index;
            str_year = years_compare[index];
            break;
        }//比较找一下是哪一年,更新year值
    }

    size_t search_year = base.find(str_year);
    if (search_year == base.size() - 4)
    {
        size_t search_day = base.find_first_of("0123456789");
        str_day.push_back(base[search_day]);
        if (isdigit(base[search_day + 1]))str_day.push_back(base[search_day + 1]);
        stringstream buffer;
        buffer << str_day; buffer >> day; buffer.clear();
        if (!english_month)
        {
            size_t month_index = search_day+2;
            while (!isdigit(base[month_index]))month_index++;
            while (isdigit(base[month_index]))
            {
                str_month.push_back(base[month_index]);

                month_index++;
            }
            buffer << str_month; buffer >> month;
        }

    }
    else
    {
        size_t month_index = 5;
        while (isdigit(base[month_index]))
        {
            str_month.push_back(base[month_index]);
            month_index++;
        }
        month_index++;
        while (isdigit(base[month_index]))
        {
            str_day.push_back(base[month_index]);
            month_index++;
        }
        buffer << str_month; buffer >> month; buffer.clear();
        buffer << str_day; buffer >> day;
    }
}
int main(int argc, char **argv) {
    const string testfilelocation = argv[1];

    ifstream datetestgetlineinput(testfilelocation);
    if (datetestgetlineinput)cout << "创建名为datetestgetlineinput的文件输入流成功,文件位置: " << testfilelocation << endl;
    else cout << "创建名为datetestgetlineinput的文件输入流失败" << endl;
    string datestr;
    while (!datetestgetlineinput.eof())
    {
        cout << "输入要转化为标准格式的日期字符串: ";
        getline(datetestgetlineinput, datestr);
        cout << datestr << endl;
        YearMonthDay date(datestr);
        datestr.clear();
        cout << date.getdatestr() << endl;
    }
    datetestgetlineinput.close();
    return 0;
}

不能转化很多类型的日期,只针对这几种
这里写图片描述

运行结果
这里写图片描述

<think>我们正在讨论C++中对string类型数据进行模糊搜索的实现方法。模糊搜索通常指允许有一定误差或不完全匹配的字符串搜索。常见方法有使用正则表达式、字符串相似度算法(如Levenshtein距离)或专门的库(如FuzzyWuzzy,但这是Python的)。在C++中,我们可以考虑以下方法: 参考引用[1]和[2]:我们知道C++标准库提供了string类,它提供了丰富的字符串操作功能,但标准库本身并没有直接提供模糊搜索功能。 参考引用[3]:虽然引用[3]是关于模糊控制的,但它提到了模糊规则和模糊化,这与字符串模糊搜索不同。因此,我们不将其应用于此处。 参考引用[4]:该引用展示了一个创建子串映射的代码片段,这可以用于实现基于子串的搜索(即允许部分匹配),但并不是严格的模糊搜索(通常指允许字符插入、删除、替换)。然而,我们可以从这个方法中得到启发,使用一种索引子串的方法来加速部分匹配。 参考引用[5]:这里提到了QT的元对象系统,与字符串搜索关系不大。 因此,我们聚焦于C++中实现模糊搜索的几种常见方法: 1. 使用正则表达式(C++11及以上支持):可以实现模式匹配,比如允许字符重复、可选字符等,但不直接支持编辑距离的模糊。 2. 使用字符串相似度算法(如Levenshtein距离): - 计算两个字符串之间的编辑距离,即从一个字符串转换到另一个字符串所需的最少单字符编辑(插入、删除、替换)次数。 - 这种方法计算量大,适合小规模数据或对性能要求不高的场景。 3. 使用第三方库: - 例如,TheFuzz(C++实现)或使用Trie树结构优化模糊搜索。 - 或者使用专门的全文搜索引擎库,如Lucene(C++版本为CLucene)。 4. 基于子串的模糊搜索(如引用[4]的方法): - 将目标字符串拆分成多个子串,并建立索引(例如,将每个子串映射到包含该子串的原始字符串的集合)。当查询时,将查询字符串拆分成子串,然后查找包含这些子串的字符串。这种方法允许部分匹配(例如,搜索“apple”时匹配到“app”和“ple”),但并不是基于编辑距离的模糊。 5. 近似字符串匹配算法(如BK树): - BK树是一种基于编辑距离的度量树,适用于快速查找与给定查询字符串编辑距离在指定阈值内的字符串。 根据需求,我们可能需要实现不同的方法。下面我将分别介绍两种常见方法:Levenshtein距离和BK树。 ### 方法1:使用Levenshtein距离计算相似度 Levenshtein距离(编辑距离)算法可以通过动态规划实现。 ```cpp #include <iostream> #include <vector> #include <algorithm> using namespace std; int levenshteinDistance(const string& s1, const string& s2) { int m = s1.length(); int n = s2.length(); vector<vector<int>> dp(m+1, vector<int>(n+1, 0)); for (int i = 0; i <= m; i++) dp[i][0] = i; for (int j = 0; j <= n; j++) dp[0][j] = j; for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { int cost = (s1[i-1] == s2[j-1]) ? 0 : 1; dp[i][j] = min({ dp[i-1][j] + 1, // 删除 dp[i][j-1] + 1, // 插入 dp[i-1][j-1] + cost // 替换 }); } } return dp[m][n]; } // 示例:在字符串集合中搜索与目标字符串编辑距离在阈值内的字符串 vector<string> fuzzySearch(const vector<string>& data, const string& query, int threshold) { vector<string> results; for (const auto& str : data) { int dist = levenshteinDistance(query, str); if (dist <= threshold) { results.push_back(str); } } return results; } ``` 这种方法在数据量很大时效率较低,因为需要计算每个字符串与查询字符串的编辑距离。 ### 方法2:BK树 BK树是一种用于快速近似字符串匹配的树结构。构建BK树需要定义距离函数(如Levenshtein距离)。 由于BK树的实现相对复杂,这里简要描述一下步骤: 1. 选择一个字符串作为根节点。 2. 插入新字符串时,计算其与当前节点的编辑距离d,如果当前节点的第d个子树上为空,则将其作为子节点;否则递归插入到该子树。 3. 查询时,给定查询字符串和阈值k,从根节点开始,计算查询字符串与当前节点的距离d,然后递归搜索距离在[d-k, d+k]范围内的子树。 由于实现代码较长,这里不展开。但我们可以使用现成的库,例如`bk-tree`(一个开源的C++ BK树实现)。 ### 方法3:使用现有库 - 如果项目允许使用第三方库,可以考虑: - Boost:Boost.StringAlgorithms库提供一些字符串处理功能,但不直接支持模糊搜索。 - Levenshtein距离的库:如`rapidfuzz`(有C++版本)或`TheFuzz`的C++端口。 - 专门的模糊搜索库:例如`fuzzywuzzy`的C++封装。 ### 方法4:基于子串匹配(如引用[4]) 引用[4]中的方法用于创建所有子串的映射,这可以用于实现子串搜索(即包含任意连续子串),但注意它创建的是所有连续子串(步长为2,针对中文字符)。我们可以修改为步长1,用于非中文字符串: ```cpp #include <unordered_map> #include <set> #include <string> #include <vector> using namespace std; void createSubStringMap(unordered_map<string, set<size_t>>& mp, const string& wholeString, size_t index) { for (size_t i = 0; i < wholeString.size(); i++) { for (size_t j = i; j < wholeString.size(); j++) { string subString = wholeString.substr(i, j - i + 1); mp[subString].insert(index); } } } // 然后,在搜索时,我们可以将查询字符串拆分成若干子串(比如长度为2或3),然后查找包含这些子串的字符串(取交集) vector<string> substringFuzzySearch(const unordered_map<string, set<size_t>>& indexMap, const vector<string>& data, const string& query, int minSubLen = 2) { // 首先,生成查询字符串的所有长度>=minSubLen的子串 set<size_t> resultSet; bool first = true; for (size_t i = 0; i < query.size(); i++) { for (size_t len = minSubLen; i + len <= query.size(); len++) { string sub = query.substr(i, len); auto it = indexMap.find(sub); if (it != indexMap.end()) { if (first) { resultSet = it->second; first = false; } else { // 取交集:这里要求所有子串都出现,但实际上模糊搜索不一定要求所有子串都出现,所以可能需要调整 set<size_t> temp; set_intersection(resultSet.begin(), resultSet.end(), it->second.begin(), it->second.end(), inserter(temp, temp.begin())); resultSet = temp; } } } } vector<string> results; for (auto idx : resultSet) { results.push_back(data[idx]); } return results; } ``` 注意:这种方法要求我们预先为所有字符串建立索引(即调用`createSubStringMap`为每个字符串构建映射,键为子串,值为该字符串在数据集中的索引)。但这种方法不是基于编辑距离的模糊,而是基于子串包含关系。 ### 结论 根据场景选择: - 小规模数据:直接使用Levenshtein距离计算。 - 大规模数据:使用BK树或建立子串索引(但注意子串索引方法不是编辑距离模糊,而是子串匹配)。 最后,注意模糊搜索的定义可能因需求而异,上述方法各有侧重。 相关问题: 1. C++中如何用正则表达式实现模糊搜索? 2. 除了Levenshtein距离,还有哪些字符串相似度算法适用于模糊搜索? 3. 如何优化大规模字符串集合的模糊搜索性能? 4. 在C++中,如何使用第三方库(如RapidFuzz)来实现模糊搜索? 5. 如何实现支持通配符的字符串模糊搜索? </think>在C++中实现`string`类型数据的模糊搜索,需要根据具体需求选择算法和技术路线。以下是几种常用方法及其实现要点: --- ### 一、基于子串索引的模糊搜索(参考引用[4]) 通过预处理构建子串索引映射(哈希表),实现高效的部分匹配: ```cpp #include <unordered_map> #include <set> #include <string> #include <vector> using namespace std; // 构建子串索引:mp[子串] = 包含该子串的原字符串索引集合 void buildSubStringMap(unordered_map<string, set<size_t>>& mp, const vector<string>& data) { for (size_t idx = 0; idx < data.size(); ++idx) { const string& str = data[idx]; for (size_t start = 0; start < str.length(); ++start) { for (size_t len = 1; len <= str.length() - start; ++len) { string sub = str.substr(start, len); mp[sub].insert(idx); // 记录子串出现的原字符串索引 } } } } // 模糊搜索:查找包含任意查询子串的字符串 vector<string> fuzzySearch(const unordered_map<string, set<size_t>>& indexMap, const vector<string>& data, const string& query) { set<size_t> resultIndexes; // 生成查询字符串的所有可能子串 for (size_t start = 0; start < query.length(); ++start) { for (size_t len = 1; len <= query.length() - start; ++len) { string sub = query.substr(start, len); if (indexMap.count(sub)) { const auto& indexes = indexMap.at(sub); resultIndexes.insert(indexes.begin(), indexes.end()); } } } // 转换为结果 vector<string> results; for (auto idx : resultIndexes) { results.push_back(data[idx]); } return results; } ``` **特点**: - 时间复杂度:索引构建$O(N \cdot L^2)$,搜索$O(K)$($K$为匹配子串数量) - 支持任意位置子串匹配 - 内存消耗较大(存储所有子串) --- ### 二、基于编辑距离的模糊匹配 使用动态规划计算Levenshtein距离(最小编辑次数): ```cpp #include <algorithm> #include <vector> int editDistance(const string& a, const string& b) { vector<vector<int>> dp(a.size()+1, vector<int>(b.size()+1, 0)); // 初始化边界条件 for (size_t i = 0; i <= a.size(); ++i) dp[i][0] = i; for (size_t j = 0; j <= b.size(); ++j) dp[0][j] = j; // 动态规划计算 for (size_t i = 1; i <= a.size(); ++i) { for (size_t j = 1; j <= b.size(); ++j) { int cost = (a[i-1] == b[j-1]) ? 0 : 1; dp[i][j] = min({ dp[i-1][j] + 1, dp[i][j-1] + 1, dp[i-1][j-1] + cost }); } } return dp[a.size()][b.size()]; } // 阈值过滤:返回编辑距离≤threshold的字符串 vector<string> fuzzyMatch(const vector<string>& data, const string& query, int threshold) { vector<string> results; for (const auto& str : data) { if (editDistance(str, query) <= threshold) { results.push_back(str); } } return results; } ``` **特点**: - 支持错字、漏字、多字等模糊场景 - 时间复杂度:$O(N \cdot M \cdot K)$($M$为字符串平均长度) - 适合短文本和小规模数据集 --- ### 三、正则表达式匹配(标准库实现) ```cpp #include <regex> #include <vector> vector<string> regexSearch(const vector<string>& data, const string& pattern) { vector<string> results; regex reg(pattern); for (const auto& str : data) { if (regex_search(str, reg)) { results.push_back(str); } } return results; } ``` **示例**: ```cpp // 查找包含"file"后跟任意数字的文件名 auto files = regexSearch(fileNames, "file\\d+"); ``` --- ### 四、使用第三方库 1. **Boost.Regex**:增强版正则表达式 ```cpp #include <boost/regex.hpp> boost::regex reg("模糊规则"); ``` 2. **FuzzyWuzzy**(需集成Python或使用C++移植版):基于编辑距离的优化匹配 3. **ICU库**:支持unicode模糊匹配和音形转换(如中文拼音搜索) --- ### 五、多模式混合优化方法 1. **索引优化**:对长文本使用倒排索引(参考引用[4]) 2. **分级过滤**: - 先用简单规则(如首字母匹配)快速筛选 - 再用编辑距离精细匹配 3. **并行计算**:使用`std::async`并行匹配 ```cpp // 示例:分级过滤 vector<string> hybridSearch(const vector<string>& data, const string& query, int threshold) { vector<string> candidates; // 1. 首字母快速过滤 for (const auto& str : data) { if (str[0] == query[0]) { candidates.push_back(str); } } // 2. 精细编辑距离匹配 return fuzzyMatch(candidates, query, threshold); } ``` --- ### 选择建议 | **场景** | **推荐方法** | **优势** | |----------------------|-------------------------|-----------------------------------| | 部分匹配(子串搜索) | 子串索引法 | 速度最快,支持任意片段查询 | | 拼写纠错 | Levenshtein编辑距离 | 容错能力强 | | 复杂规则匹配 | 正则表达式 | 模式描述灵活 | | 多语言支持 | ICU库 | 支持unicode、拼音转换等 | | 海量数据 | 子串索引+分级过滤 | 平衡效率与内存 | > 提示:引用[3]中提到的模糊控制算法属于控制理论范畴,与字符串模糊搜索无直接关联[^3]。 --- ### 相关问题: 1. 如何在C++中实现中文拼音的模糊搜索? 2. 如何优化子串索引方法的内存占用? 3. 编辑距离算法有哪些性能优化技巧? 4. 模糊搜索在实时系统中的性能瓶颈如何解决? 5. C++20标准对字符串搜索提供了哪些新特性?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值