Hey guys, the following code is part of a program I am working on and as a newbie to c++ I have come across a problem. As you can see when the case is J the int J is increased by 1 but how do I go about doing this if for example instead of J I want to use JJ?

Thanks in advance for any help.

ifstream file("c:\file.txt");

    if (file.is_open())
  {
    while (! file.eof() )
    {
        while (file.get(ch))
         {
		switch (ch) {
                             case 'j':
                             J++;
                            }
           }
     }
  }

Dani AI

Generated

The original code increments J for a single 'j'. To count a two-character sequence like "jj" (call it JJ) the usual options are: remember the previous character while streaming, or read the whole file and scan for the substring. 's ideas (packing two chars into an integer, or storing the previous value) are valid, but packing is unnecessary complexity for this problem. Storing the previous character is simple and memory efficient; reading into a string and scanning is simpler to implement and easier to reason about for small-to-moderate files.

Example (read whole file and count both single 'j' and overlapping "jj" occurrences):

#include <fstream>
#include <iterator>
#include <string>

std::ifstream file(R"(c:\file.txt)");
if (!file) { /* handle error */ }

std::string content((std::istreambuf_iterator<char>(file)),
                    std::istreambuf_iterator<char>());

std::size_t countJ = 0, countJJ = 0;
for (std::size_t i = 0; i < content.size(); ++i) {
    if (content[i] == 'j') ++countJ;
    if (i + 1 < content.size() && content[i] == 'j' && content[i + 1] == 'j')
        ++countJJ; // counts overlapping matches: "jjj" -> two "jj"
}

Notes and troubleshooting:

  • Avoid while (!file.eof()); prefer streaming (file.get) or reading into a string via iterators as above.
  • Use R"(c:\file.txt)" or escape backslashes ("c:\\file.txt") when specifying Windows paths.
  • For very large files, prefer a streaming solution that keeps only the previous character in memory (this is what suggested).
  • If case-insensitive matching is needed, normalize characters with std::tolower(static_cast<unsigned char>(ch)).
  • If non-overlapping matches are required (count "jj" only once in "jjj"), advance the index when a match is found (e.g., ++i after incrementing countJJ).

Recommended Answers

All 3 Replies

switch only operate on a single integer value... however since a char is smaller than an integer I suppose you could stack it in one value and then do the switch

value = ((value << 8) & 0xff) |file.getch() ;
   switch( value )
   {
      case ('j' << 8 | 'j'):
   }

Assuming the old value is saved in value between each loop, this _should_ work since 'j'<<8 | 'j' is a constant expression that the compiler should be able to figure out (else you would have to write it down yourself to get the integer value.
This wont work if you want to use both one and two letter combinations in the same switch thought, unless you are willing to list _all_ possible combinations with the single char you want to match (ie case 'a'<<8 | 'j': case 'b' <<8 | 'j': ... ...
And simpler way would probably be to store the last value read and go from there.

Hi thanks for your reply, is there also a way to do this using IF statements?

Thanks

ofcourse, there is plenty of ways to do this... you could for example store the previous value...

current_value = file.getc() ;
if( current_value == 'j' && previous_value == 'j') {
    // We got our value...
}
previous_value = current_value ;
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.