繁体   English   中英

C ++:在字符串中找到一个字符,然后在前面的字符之后找到另一个字符

[英]C++: Find a char in a string, then find another char following previous char

首先道歉,如果标题有点含糊。 我是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()函数是否正确使用的一些建议?

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

注意事项

假设所有出现的“ 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. string :: find()返回的位置为无符号整数,而不是布尔值
  2. 每当有'if'时,就没有'else'...

正确的功能应为:

    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两次-意味着每个字符串都被扫描了两次。 我们可以保存一张通行证吗? 当然。

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

#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只有在下列条件:

  • 字符串包含字符“ c”
  • 每次出现“ c”后都没有“ h”

因此功能可能是:

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);
    }
}
//...

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

小优化:无需进行其他查找,只需检查下一个字符:

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;
}

假设您需要: 每次在其中带有'c'的单词时,请查看其后是否带有'h'。 如果确实如此,则将单词假为假

由于您恰好在h之后需要c ,因此可以使用:

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

注意:

如果存在多个c即使其他c具有h也为字符串返回true 像: "abc_ch"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM