C ++:在字符串中查找字符,然后在上一个字符

时间:2017-04-23 08:51:28

标签: c++

如果标题有点含糊不清,首先道歉。我是C ++的新手,我仍在努力理解语言的复杂性。

基本上我正在处理一个很大的单词列表(实际上是一个字典),它存储在向量中。

我对此的思考过程是我想找到所有带有'c'的单词。每次有一个带有“c”的单词时,请查看它后面是否有“h”。如果确实如此,则将该单词丢回为假。希望得到像这样的话:

-carbon
-carry
etc etc

到目前为止,我已尝试实现一些代码,这是我到目前为止所做的:

bool hasCWithNoH(string wordName)
{
    if (wordName.find('c'))
    {
        if (wordName.find('ch'))
        {
            return false;
        }
    }
}

在主{}源文件中由此调用:

void findCWithNoH()
{
    cout << "List of words found with a 'c' but with no following 'h': " << endl;
    for (Word word : words)
    {
        string testWord = word.getName();
        if (word.hasCWithNoH(testWord))
        {
            cout << testWord << endl;
        }
    }
}

结果是这样的:

czarowitz
czech
czechic
czechoslovakian
czechs
h
ha
haaf
haak
haar
habeas-corpus
habenaria

结果发现每个单词都以'c'和'h'开头(不是我想要的)。

我认为我没有正确使用find()函数和循环,请问如何设置函数以及find()函数是否使用正确的函数?

如果需要更多解释,请发表评论,我可以进一步阐述。

4 个答案:

答案 0 :(得分:3)

  

注意

     

假设所有出现的'c'都不应该在'h'之后,   这应该有效。

当没有c存在时,您不会返回false 请检查string::find的返回值

  

返回值   第一场比赛的第一个角色的位置。   如果未找到匹配项,则函数返回string :: npos。

将您的功能更改为

bool hasCWithNoH(string &wordName)
{
    if (wordName.find('c')!=string::npos)
    {
        if (wordName.find("ch")!=string::npos)//Also use double quotes for string "ch"
        {
            return false;
        }
        else
        {
            return true;
        }
    }
    else
    {
        return false; //Because word does not contain c.
    }
}

答案 1 :(得分:2)

有两个问题:

  1. string :: find()将位置作为unsigned int返回,而不是bool值
  2. 只要有“如果&#39;”,你就没有&#39;其他&#39; ...
  3. 正确的功能应该是:

        bool hasCWithNoH(string wordName) {
            if (wordName.find("c") != string::npos) {
                if (wordName.find("ch") != string::npos) {
                    return false;
                } else  {
                    return true;
                }
            } else {
                return false;
            }
        }
    

    编辑:由于最好的答案表明几乎相同的代码更改,同时提供更好的解释,我特此更新并提供不同的东西。

    我们注意到名为string :: find两次的程序 - 意味着每个字符串被扫描两次。我们可以保存一张票吗?当然。

    让我们首先设置测试程序。我们有测试数据和预期结果。如果实际结果有点不同,程序将输出实际结果并说“&#34;失败&#34;。

    #include <string>
    #include <vector>
    #include <algorithm>
    #include <iostream>
    
    using namespace std;
    
    bool hasCWithNoH(const string& wordName) {
        return true;
    }
    
    int main() {
        string words[] = { // test data
            "czarowitz",
            "czech",
            "czechic",
            "czechoslovakian",
            "czechs",
            "h",
            "ha",
            "haaf",
            "haak",
            "haar",
            "habeas - corpus",
            "habenaria"
        };
    
        string expect_result[] = {
            "czarowitz", 
            "habeas - corpus"
        }; 
    
        vector<string> actual_result;
    
        for (string word : words) {
            if (hasCWithNoH(word)) {
                actual_result.push_back(word);
            }
        }
    
        if (actual_result.size() == 2 && 
            equal(expect_result, expect_result + 2, actual_result.begin())) {
            cout << "Test passed" << endl;
        } else {
            cout << "Test failed, the following words are returned:" << endl;
            for_each(actual_result.begin(), actual_result.end(), [](const string& e) { std::cout << e << endl; });
        }
    
        return 0;
    }
    

    当然,使用虚拟函数测试用例失败。

    如果我们将函数更改为上面答案中的函数,则测试将通过。

    现在让我们实现一次通过功能。根据描述以及提供的测试数据,我们知道只有满足以下条件时函数才应返回true

    • 该字符串包含字符&#39; c&#39;
    • 没有&#39; h&#39;紧接着每次出现&#39; c&#39;

    所以功能可以是:

    bool hasCWithNoH(const string& wordName) { // use reference type wherever possible
        bool match = false; // By default, it doesn't match
    
        for (string::const_iterator it = wordName.begin(); it != wordName.end(); ++it) {
            if (*it == 'c') {
                match = true; // If we see there's a 'c', it becomes a candidate...
                if (it != (wordName.end() - 1) && *(it + 1) == 'h') {
                    match = false;
                    break; // But if later we see an 'h' right behind 'c', it's rejected immediately
                }
            }
        }
    
        return match;
    }
    

    现在案件再次通过。

    为了改进,我们注意到该函数只接受std :: string。嗯,最好不要依赖某种数据类型。例如,如果调用者具有C风格的字符串,我们不应强制他在调用函数之前将其转换为std :: string。所以我们可以使用模板功能:

    template <class Iterator>
    bool hasCWithNoH(Iterator first, Iterator last) {
        bool match = false;
    
        for (Iterator it = first; it != last; ++it) {
            if (*it == 'c') {
                match = true;
                if (it != last - 1 && *(it + 1) == 'h') {
                    match = false;
                    break;
                }
            }
        }
    
        return match;
    }
    

    请注意,现在需要我们按以下方式调用该函数:

    //...
    for (string word : words) {
        if (hasCWithNoH(word.begin(), word.end())) {
            actual_result.push_back(word);
        }
    }
    //...
    

    运行程序,我们再次看到测试用例。

答案 2 :(得分:0)

小优化:不需要再做另一个查找,只需检查下一个字符:

bool hasCWithNoH(const string & wordName)
{
    size_t pos = wordName.find('c');
    if ( pos == string::npos )
        return false;

    while ( pos !=string::npos )
    {
        if (  pos +1  < wordName.size() ) {
                if (  wordName[pos+1] == 'h' ) 
                    return false;
        }
        else
            return true;

        pos = wordName.find('c', pos+1);
    }
    return true;
}

答案 3 :(得分:0)

  

假设您需要: 每次有一个带有'c'的单词时,请查看它后面是否有'h'。如果确实如此,则将该单词丢回为假

由于c完全需要h,您可以使用:

if( string[ string.find_first_of( 'c' ) + 1 ] == 'h' ){
    return false;
} else {
    return true;
}

注意:

如果有多个true,即使其他cc

也会为字符串返回h。喜欢:"abc_ch"