【问题标题】:Questions about std::begin() for std::string array and "grep" function alternatives?关于 std::string 数组和“grep”函数替代的 std::begin() 的问题?
【发布时间】:2021-12-01 10:53:05
【问题描述】:

编辑: 这与我对答案here的兴趣不谋而合:

目前,我一直在使用它,但是如果需要找到 str3、str4、....,这显然是有问题的。

size_t find(const std::string& line, const std::string& str1, const std::string& str2, int pos) {
    int eol1 = line.find(str1,pos);
    int eol2 = line.find(str2,pos);
    return (eol1 < eol2) ? eol2 : eol1;
}

size_t find(const std::string& line, std::vector<std::string> vect, int pos ) {
    int eol1; 
    eol1 = 0;
    for (std::vector<std::string>::iterator iter = vect.begin(); iter != vect.end(); ++iter){
        //std::cout << *iter << std::endl;
        int eol2 = line.find(*iter, pos);
        if (eol1 == 0 && eol2 > 0)
            eol1 = eol2;
        else if ( eol2 > 0 && eol2 < eol1)
            eol1 = eol2;
    }
    return eol1;
}

问题: 为什么 std::begin() 不能用于静态而不能用于动态,什么是最简单或最有效的替代方案?

奇怪的是,我经常在 Fortran 例程中使用两三个词搜索,但在 c++ 社区中没有一个紧凑的“多字符串搜索”功能。如果您需要此功能,是否必须实现复杂的“grep”系列或“regex”?

 bool contains(const std::string& input, const std::string keywords[]){//cannot work
    //std::string keywords[] = {"white","black","green"}; // can work
    return std::any_of(std::begin(keywords), std::end(keywords),
        [&](const std::string& str) {return input.find(str) != std::string::npos; });
}

为什么矢量化版本也不能工作?

bool contains(const std::string& input, const std::vector<std::string> keywords){
// do not forget to make the array static!
//std::string keywords[] = {"white","black","green"};
return std::any_of(std::begin(keywords), std::end(keywords),
    [&](const std::string& str) {return input.find(str) != std::string::npos; });
}

附加: 在学习“参数包”的路上,但还是有问题……

//base
size_t fin(const std::string& line, const std::string& str1) {
    std::cout << var1 << std::endl;
    return line.find(str1);
}
//vargin
template <typename... Types>
size_t fin(const std::string& line, const Types... var1) {
    return fin(line, var1...);
}

【问题讨论】:

  • 当您说“静态”和“动态”时,我假设您的意思是普通数组(用于“静态”)和指针(用于“动态”),对吗?然后考虑指针指向的内容:它只指向一个对象,并且语言中没有内置知识表明该单个对象后面可能有更多数据。当(和你的程序)知道有更多对象时,系统如何知道它们何时结束?
  • 请花些时间刷新the help pages,尤其是"What topics can I ask about here?""What types of questions should I avoid asking?"。也可以通过tour 阅读How to Ask 好问题和this question checklist。请每个问题一个问题。
  • const std::string keywords[] 不是静态的 动态的 - 它只是一个函数参数经历数组衰减到一个指针。如果您不希望原始数组表现得像原始数组一样,只需传递 std::vectorstd::array 或数组引用即可。
  • 顺便说一句,如果术语“矢量化”是指使用std::vector,那么这不是正确的术语。向量化是如何并行使用多个值进行计算。
  • 另外,作为参数const std::string keywords[] 被解析为const std::string* keywords。它不是一个数组,只是一个指针。

标签: c++


【解决方案1】:

从不同的角度来看,字符串数组可能不是检查的最佳容器。我建议使用 std::set。

#include <cassert>
#include <iostream>
#include <set>
#include <string>
#include <string_view>

std::set<std::string_view> keywords{ "common", "continue", "data", "dimension" };
std::set<char> delimiters{ ' ', ',' , '.', '!', '?', '\n' };

inline bool is_keyword(const std::string_view& word)
{
    return keywords.find(word) != keywords.end();
}

inline bool is_delimiter(const char c)
{
    return delimiters.find(c) != delimiters.end();
}

bool contains_keyword(const std::string& sentence)
{
    auto word_begin = sentence.begin();
    auto word_end = sentence.begin();

    do
    {
        // create string views over each word 
        // words are found by looking for delimiters
        // string_view is used so no data is copied into temporaries
        while ((word_end != sentence.end()) && !is_delimiter(*word_end)) word_end++;
        std::string_view word{ word_begin,word_end };

        // stop as soon as keyword is found
        if (is_keyword(word)) return true;

        // skip delimiters
        while ((word_end != sentence.end()) && is_delimiter(*word_end)) word_end++;
        word_begin = word_end;

    } while (word_end != sentence.end());

    return false;
}

int main()
{
    std::string sentence_with_keyword{ "this input sentence, has keyword data in it" };
    bool found = contains_keyword(sentence_with_keyword);
    assert(found);

    if (found)
    {
        std::cout << "sentence contains keyword\n";
    }

    std::string sentence_without_keyword{ "this sentence will not contain any keyword!" };
    found = contains_keyword(sentence_without_keyword);
    assert(!found);

    return 0;
}

【讨论】:

  • 好点,大量使用的向量容器阻止了我对的思考,但请注意,目的是查找是否有任何指定的单词出现在长句中。
  • 啊好的,更新了示例。我还从字符串转移到 string_views 以避免任何不必要的数据复制。并添加了可以在字符串中查找关键字的功能。 (您可能需要微调分隔符集)
【解决方案2】:
  1. 为什么 std::begin() 不能用于静态,而不能用于动态,最简单或最有效的替代方法是什么?

另一个答案中的代码指的是一个静态局部变量

// do not forget to make the array static!
static std::wstring keywords[] = {L"white",L"black",L"green", ...};

这里的关键字 static 是一个快捷方式:它将keywords 变成一个全局变量,但作用域是局部的。因此,表达作者所说内容的更清晰的方式可能是:

// put this here...
std::wstring keywords[] = {L"white",L"black",L"green", ...};
    
bool ContainsMyWordsNathan(const std::wstring& input)
{
    //... instead of here
    return std::any_of(std::begin(keywords), std::end(keywords),
      [&](const std::wstring& str){return input.find(str) != std::string::npos;});
}

如果您在函数内使用std::vector 或数组,该代码将正常工作。但是每次调用它时每次构建列表都会产生开销。

当它被全局定义时,关键字列表被构造一次并在程序运行期间留在内存中。


  1. 我经常在 Fortran 例程中使用两三个词搜索,但在 c++ 社区中没有一个紧凑的“多字符串搜索”功能。如果您需要此功能,是否必须实现复杂的“grep”系列或“regex”?

C++ 并不是一种真正紧凑的单行语言。算法标头旨在为您提供一种表达算法的方式,以明确其在做什么(std::any_ofstd::countstd::copy_if 等)。

您的代码正在搜索一个关键字,每次都执行一次。您可以考虑首先通过查找字母数字字符组来标记您的字符串,而不是对文本进行多次搜索。然后搜索一个集合或地图,看看这个词是否是关键字,正如另一个答案所暗示的那样。

它远不是一个紧凑的单线,但这是我将如何实现它:

bool is_alpha(const char c) {
    return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}

bool is_not_alpha(const char c) {
    return !is_alpha(c);
}

std::unordered_set<std::string_view> keywords = { "red", "blue", "yellow" };

bool has_keyword(std::string_view input) {
    auto it = input.begin();
    while (it != input.end()) {
        // find a word
        auto word_start = std::find_if(it, input.end(), is_alpha);
        auto word_end = std::find_if(word_start, input.end(), is_not_alpha);
        std::string_view token { &*word_start, static_cast<size_t>(word_end - word_start) };
        
        // test if it's a keyword
        if (keywords.find(token) != keywords.end())
            return true;

        it = word_end;
    }

    return false;
}

【讨论】:

  • “静态”这个词在 c++ 中的意思太多了,我学得还不够。
猜你喜欢
  • 2016-09-12
  • 2015-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-01
  • 2021-05-29
  • 2015-08-11
相关资源
最近更新 更多