在字符串中查找确切的子str

Find an exact substr in a string

本文关键字:str 字符串 查找      更新时间:2023-10-16

>我有一个包含以下文本的文本文件

许可证 ="123456">

通用许可证 ="56475655">

我想搜索License以及GeneralLicense

while (getline(FileStream, CurrentReadLine))
{
    if (CurrentReadLine.find("License") != std::string::npos)
    {
        std::cout << "License Line: " << CurrentReadLine;
    }
    if (CurrentReadLine.find("GeneralLicense") != std::string::npos)
    {
        std::cout << "General License Line: " << CurrentReadLine;
    }
}

由于单词License也出现在单词GeneralLicense所以if-statement行中if (CurrentReadLine.find("License") != std::string::npos)两次变为真。

如何指定要搜索确切的子字符串?

更新:我可以反转某些答案提到的顺序,或者检查License是否在索引零处。但是,我们是否可以寻找确切的匹配项(类似于我们在大多数编辑器中拥有的东西,例如MS Word等(。

while (getline(FileStream, CurrentReadLine))
{
    if (CurrentReadLine.find("GeneralLicense") != std::string::npos)
    {
        std::cout << "General License Line: " << CurrentReadLine;
    }
    else if (CurrentReadLine.find("License") != std::string::npos)
    {
        std::cout << "License Line: " << CurrentReadLine;
    }
}

更健壮的搜索称为正则表达式:

#include <regex>
while (getline(FileStream, CurrentReadLine))
{
    if(std::regex_match(CurrentReadLine,
        std::regex(".*\bLicense\b.*=.*")))
    {
        std::cout << "License Line: " << CurrentReadLine << std::endl;
    }
    if(std::regex_match(CurrentReadLine,
        std::regex(".*\bGeneralLicense\b.*=.*")))
    {
        std::cout << "General License Line: " << CurrentReadLine << std::endl;
    }
}

\b 转义序列表示单词边界。

.* 表示"任何字符序列,包括零个字符">

编辑:您也可以使用regex_search而不是regex_match来搜索匹配的子字符串,而不是使用.*来覆盖不匹配的部分:

#include <regex>
while (getline(FileStream, CurrentReadLine))
{
    if(std::regex_search(CurrentReadLine, std::regex("\bLicense\b"))) 
    {
        std::cout << "License Line: " << CurrentReadLine << std::endl;
    }
    if(std::regex_search(CurrentReadLine, std::regex("\bGeneralLicense\b")))
    {
        std::cout << "General License Line: " << CurrentReadLine << std::endl;
    }
}

这与您的代码更匹配,但请注意,如果在等号之后也找到关键字,它将被触发。如果您想要最大的鲁棒性,请使用regex_match并准确指定整条生产线应匹配的内容。

您可以检查子字符串出现的位置是否位于索引零处,或者初始位置前面的字符是否为空格:

bool findAtWordBoundary(const std::string& line, const std::string& search) {
    size_t pos = line.find(search);
    return (pos != std::string::npos) && (pos== 0 || isspace(line[pos-1]));
}

难道没有什么健壮的(标志或其他东西(可以指定来寻找完全匹配的吗?

在某种程度上,find已经在寻找完全匹配。但是,它将字符串视为表示单个字符的无意义数字序列。这就是为什么std::string类缺少"全词"的概念,该概念存在于库的其他部分,例如正则表达式。

您可以编写一个函数,该函数首先测试最大的匹配项,然后返回您想要的有关匹配项的任何信息。

有点像:

// find the largest matching element from the set and return it
std::string find_one_of(std::set<std::string, std::greater<std::string>> const& tests, std::string const& s)
{
    for(auto const& test: tests)
        if(s.find(test) != std::string::npos)
            return test;
    return {};
}
int main()
{
    std::string text = "abcdef";
    auto found = find_one_of({"a", "abc", "ab"}, text);
    std::cout << "found: " << found << 'n'; // prints "abc"
}

如果所有匹配项都以 pos 0 开头,并且没有一个是另一个的前缀,则以下内容可能有效

if (CurrentReadLine.substr( 0, 7 ) == "License")

您可以标记字符串,并使用搜索关键字和标记进行全面比较

例:

#include <string>
#include <sstream>
#include <vector>
#include <iostream>
auto tokenizer(const std::string& line)
{
    std::vector<std::string> results;
    std::istringstream ss(line);
    std::string s;
    while(std::getline(ss, s, ' '))
        results.push_back(s);
    return results;
}
auto compare(const std::vector<std::string>& tokens, const std::string& key)
{
    for (auto&& i : tokens)
        if ( i == key )
            return true;
    return false;
}
int main()
{
    std::string x = "License = "12345"";
    auto token = tokenizer(x);
    std::cout << compare(token, "License") << std::endl;
    std::cout << compare(token, "GeneralLicense") << std::endl;
}