【问题标题】:Comparing string elements of two vector<Structs>比较两个vector<Structs>的字符串元素
【发布时间】:2017-03-28 00:18:13
【问题描述】:

在这里继续我之前的问题:

Accessing local variables from void functions

我已经能够获得我需要的数据,现在我正在尝试比较传递给函数的每个 struct 元素的 string name 属性。

这是我当前的代码:

#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <iostream>

using namespace std;

struct Nutrient {
    string name, units;
    double amount, calories;
};

struct Recipe {
    string title;
    double servings;
};

struct Ingredient {
    string name, units;
    double amount;
};

vector<Nutrient> readNutrients(istream& fin) {

    vector<Nutrient> nutrients;

    /**ifstream in(input_file.c_str());*/

    string line;

    while (getline(fin, line)) {

        Nutrient n;

        int pos = line.find(';');
        n.name = line.substr(0, pos);
        line = line.substr(pos + 1);

        istringstream iss(line);

        iss >> n.amount >> n.units >> n.calories;
        nutrients.push_back(n);
    }

    return nutrients;

}

Recipe readRecipe(istream& fin) {

    Recipe recipe;

    string line;

    int lineCount = 0;

    while (getline(fin, line)) {

        lineCount++;
        istringstream iss(line);

        if (lineCount == 1) {
            iss >> recipe.title;
        }
        else if (lineCount == 2) {
            iss >> recipe.servings;
        }
    }
    return recipe;
}

vector<Ingredient> readIngredients(istream& fin) {

    vector<Ingredient> ingredients;

    string line;
    string title; // Just grabs, doesnt return
    double servings; // Just grabs, doesnt return

    int lineCount = 0;


    while (getline(fin, line)) {

        Ingredient g;

        lineCount++;
        istringstream iss(line);

        if (lineCount == 1) {
            iss >> title;
        }
        else if (lineCount == 2) {
            iss >> servings;
        }
        else {
            iss >> g.amount >> g.units >> ws;
            getline(iss, g.name, '\n');
            cout << g.name << "\n";
            ingredients.push_back(g);
        }
    }
    return ingredients;
}

bool itemsMatch(vector<Nutrient>& nut, vector<Ingredient>& ing) {
    int matchCount = 0;

    for (int i = 0; i < nut.size(); i++) {
        for (int j = 0; j < ing.size(); j++) {
            if (nut[i].name == ing[j].name) {
                cout << nut[i].name << " matched " << ing[j].name << endl;
                cout << "\n";
            }
            else {
                cout << nut[i].name << " didnt match " << ing[j].name << endl;
            }
        }
    }
    return true;
}

int main(int argc, char** argv) {
    vector<Nutrient> nutri;
    vector<Ingredient> ingri;
    Recipe rec;
    bool match;

    ifstream finNutr(argv[1]);
    ifstream finIngr(argv[2]);
    ifstream finReci(argv[2]);

    nutri = readNutrients(finNutr);
    ingri = readIngredients(finIngr);
    rec = readRecipe(finReci);

    match = itemsMatch(nutri, ingri);

    return 0;
}

bool itemsMatch() 是造成麻烦的原因。这是最后的输出:

graham crackers
milk chocolate
marshmallows
graham crackers didnt match graham crackers
graham crackers didnt match milk chocolate
graham crackers didnt match marshmallows
milk chocolate didnt match graham crackers
milk chocolate didnt match milk chocolate
milk chocolate didnt match marshmallows
cheese, swiss didnt match graham crackers
cheese, swiss didnt match milk chocolate
cheese, swiss didnt match marshmallows
marshmallows didnt match graham crackers
marshmallows didnt match milk chocolate
marshmallows matched marshmallows

可见,有几个字符串匹配,但出于某种原因,它说它们不匹配,我不知道为什么。

arg1 内容

graham crackers; 2 squares 59
milk chocolate; 1 bar 235
cheese, swiss; 1 oz 108
marshmallows; 1 cup 159

arg2 内容

S'mores
2
4 squares graham crackers
1 bar milk chocolate
2 large marshmallows

【问题讨论】:

  • 使用调试器逐步完成。
  • @chris 调试器?我不熟悉 C++ 调试器。它是内置的吗?
  • 取决于您使用的是什么。大多数 IDE 都内置了调试器,编译器附带了一个可以从命令行使用的调试器。阅读有关如何使用调试器的教程非常值得。
  • 您是否验证了这些向量包含您认为它们包含的内容?如果您没有调试器,请使用循环打印每个内容。此外,您应该编辑您的问题以提供minimal reproducible example
  • 附带说明,您将按值 传递给itemsMatch(),因此它将在内存中复制它们的数据。您应该通过 by reference 传递向量。另外,请查看 STL 的 std::find_if() 算法,而不是手动搜索。

标签: c++ string function vector struct


【解决方案1】:

我的猜测是你的输入文件有 DOS 行结尾,这是两个字符的序列:"\r\n"

当您使用getline 时,它将读取到\n,因此\r 将包含在您从文件中读取的字符串中。这意味着您从第二个文件中读取的成分是这些字符串:

S'mores\r
2\r
4 squares graham crackers\r
1 bar milk chocolate\r
2 large marshmallows

请注意,最后一行后没有 "\r\n",因此读取“marshmallows”时没有 \r 回车符。

在另一个文件中,成分不在行尾,因此\r 回车符不会被读入name 字符串的营养成分。这意味着当您比较要比较的字符串时:

"graham crackers" == "graham crackers\r" -> false
"milk chocolate" == "milk chocolate\r" -> false
"marshmallows" == "marshmallows" -> true

解决方案是手动去除\r 回车符,或者转换您的输入文件以删除回车符(或者停止使用Windows,它有这种愚蠢的约定,会给初学者带来无穷无尽的问题)。

要删除\r 字符,您可以在每个getline 之后执行此操作:

while (getline(fin, line)) {
    if (!line.empty() && line.back() == '\r')
        line.pop_back();

这将从行尾删除\r(如果存在)。

或者如果你被困在过去并且无法使用 C++11:

while (getline(fin, line)) {
    if (!line.empty() && line[line.length()-1] == '\r')
        line.resize(line.length()-1);

【讨论】:

  • 昨晚我放弃了晚上,我运行了一个简单的ing[x].name.length()并发现有隐藏的字符;但我累了,今晚要查找解决方案。今晚我会试试这个,如果它有效,请给出答案并投票!
  • 它有效 :) 我已经对其进行了测试,以确认它解释了您看到的行为,并且可以修复它。
  • 太棒了!用假数据运行程序最终让我得出结论,它必须是向量中的数据;它只在name 属性上失败,所以这是最合乎逻辑的结果。
【解决方案2】:

您发布的比较代码很好。当然你的函数总是会返回 true,这是没有意义的,但这不是问题。

问题出在结构体的数据中,因此数据(例如,您从中读取的文件)或用于将数据读取到结构体的代码存在缺陷。

要么打印您的结构以确认它们包含您认为它们所做的确切内容(当然打印您的向量的大小)或使用 调试器,例如 gdb.


专业提示:这里不是问题,但请考虑更改您的原型:

bool itemsMatch(vector<Nutrient> nut, vector<Ingredient> ing)

到这里:

bool itemsMatch(vector<Nutrient>& nut, vector<Ingredient>& ing)

这样您就不必复制整个向量,而只需传递对它们的引用,这对于大向量来说要快得多! =)

【讨论】:

  • 感谢参考传递的提示。我已经发布了我的完整代码,看看是否有人看到了我没有看到的东西。我开始怀疑它是否在我使用 getline(iss, g.name, '\n') 的部分周围的值不是真正匹配的。
  • @pstatix 我现在看到了,但您似乎找到了答案!很高兴我提供了帮助,并为您的问题 +1! :)
【解决方案3】:

你应该像这样更改代码然后测试,检查我没有测试的代码的语法:)

auto itring = ing.begin();

for (auto itrnut = nut.begin(); itrnut != nut.end(); itrnut++, itring++ ) {
            if (itrnut->name == itring->name) {
                cout << itrnut->name << " matched " << itring->name << endl;
                cout << "\n";
        }
    }

【讨论】:

  • 不管错与否,仅仅说“将您的代码更改为此”并不是很有帮助。为什么?原版有什么问题,如何解决?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-08
  • 2021-09-01
  • 1970-01-01
  • 2011-08-04
  • 1970-01-01
相关资源
最近更新 更多