search for words in a file

Hi, I have a program I'm currently working on where I'm trying to read a particular city from a file. Here is the content of the file below:

Oakland : Lake Chalet

San Francisco : Barretta

Berkeley : Chez Paniz

Basically, my goal is to search for a particular city and then retrieve the restaurant associated with it. So for example, if I search for Oakland then I would retrieve Lake Chalet. However, I'm having trouble figuring out how to do this. Could someone please take a look at this for me if possible? Thank you

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

#include <iostream>
#include <fstream>

int main(int argc, const char * argv[])
{
    std::ifstream read;
    std::string file = "FilePractice.doc";
    read.open("FilePractice.doc", std::ios::in);
    std::string output, scope;
    int i  = 0;
    bool on = false;
    std::string word = "Oakland";
    
    while(getline(read,output))
    {
        if(output.find(word) != std::string::npos)
            on = true;
        if(on && (scope != word || scope != ":"))
            scope += output;
        if(read.peek() == '\n')
            on = false;
        
        i++;
    }
    std::cout << scope << std::endl;
        read.close();
    
    

    return 0;
}
You might want to use std::istringstream from the <sstream> header. Then you can read from the line the same way you can with std::cin, std::ifstream, etc.

1
2
3
4
std::istringstream iss(line);
std::getline(iss, city, ':');
std::getline(iss, restaurant);
...


You might also have to come up with a way to "trim" whitespaces from the ends of the strings because "Oakland " will not compare equal to "Oakland".
Last edited on
What are you trying to do? Do you try to find multiple locations? Since you never break the loop?

This is one approach to find the city and return the restaurant:
1
2
3
4
5
6
7
8
9
10
11
12
13
    while(getline(read,output))
    {
        const std::size_t pos = output.find(":");
        if(pos != std::string::npos)
        {
          const std::size_t pos_city = output.find(word, 0, pos);
          if(pos_city != std::string::npos)
          {
            scope = output.substr(pos + 1);
            break;
          }
        }
    }
Not tested!
If you want the line number you might try this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    int i  = 0;
    for(; getline(read,output)); ++i)
    {
        const std::size_t pos = output.find(":");
        if(pos != std::string::npos)
        {
          const std::size_t pos_city = output.find(word, 0, pos);
          if(pos_city != std::string::npos)
          {
            scope = output.substr(pos + 1);
            break;
          }
        }
    }
Last edited on
If you want to do this by reading from a file and checking, then perhaps something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <string_view>
#include <optional>
#include <cctype>

std::string lc(std::string s) {
	for (auto& c : s)
		c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));

	return s;
}

std::string_view trim(std::string_view sv) {
	while (std::isspace(static_cast<unsigned char>(sv.back())))
		sv.remove_suffix(1);

	while (std::isspace(static_cast<unsigned char>(sv.front())))
		sv.remove_prefix(1);

	return sv;
}

std::optional<std::string> findRest(std::istream& read, std::string_view word) {
	const auto w { lc(std::string(trim(word))) };

	read.clear();
	read.seekg(0);

	for (std::string line; std::getline(read, line); ) {
		std::istringstream iss(line);
		std::string city, rest;

		std::getline(iss, city, ':');
		std::getline(iss, rest);

		if (lc(std::string(trim(city))) == w)
			return std::string(trim(rest));
	}

	return {};
}

int main() {
	const std::string file { "city.txt" };

	if (std::ifstream read { file })
		for (std::string word; std::getline(std::cin, word); )
			if (auto res { findRest(read, word) }; res)
				std::cout << word << " - " << *res << '\n';
			else
				std::cout << word << " not found\n";
		else
			std::cout << "Cannot open file\n";
}


However, in cases like this it's more usual to first read the file into a container and then search the container. Consider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <string_view>
#include <optional>
#include <unordered_map>
#include <cctype>

using Data = std::unordered_map<std::string, std::string>;

std::string lc(std::string s) {
	for (auto& c : s)
		c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));

	return s;
}

std::string_view trim(std::string_view sv) {
	while (std::isspace(static_cast<unsigned char>(sv.back())))
		sv.remove_suffix(1);

	while (std::isspace(static_cast<unsigned char>(sv.front())))
		sv.remove_prefix(1);

	return sv;
}

Data read(const std::string& fn) {
	Data data;

	if (std::ifstream read { fn })
		for (std::string line; std::getline(read, line); ) {
			std::istringstream iss(line);
			std::string city, rest;

			std::getline(iss, city, ':');
			std::getline(iss, rest);

			data[lc(std::string(trim(city)))] = std::string(trim(rest));
		}

	return data;
}

int main() {
	const std::string file { "city.txt" };
	const auto data { read(file) };

	if (!data.empty())
		for (std::string word; std::getline(std::cin, word); )
			if (const auto res { data.find(lc(std::string(trim(word)))) }; res != data.end())
				std::cout << word << " - " << res->second << '\n';
			else
				std::cout << word << " not found\n";
	else
		std::cout << "Cannot open file\n";
}

Last edited on
Sounds great, thank you for all your helps guys this has helped me a lot.

Topic archived. No new replies allowed.