Number of middle symbols

Hi there. I have a problem. I don't know how to count the number of the middle letters of the words in the sequence. I have to do it from a file and numbers counts as a word and any punctuation as a space. I have now only reading file and i guess it's wrong.

[#include <iostream>
#include <cmath>
#include <iomanip>
#include <fstream>
#include <string>
using namespace std;
const char FileName[] = "bandymas.txt";
int main ()
{
string line;
ifstream seka (FileName);
int c;

if (seka.is_open())
{

while( getline (seka, line)){

cout<<line<<endl;
c++;
}
}
seka.close();

return 0;
}]
Can you post the file, or if it is too large, a couple of paragraphs from it?
it's like: house 777 2.58 street . There is no certain file, I can create my own :D
count the number of the middle letters of the words
...
numbers counts as a word
...
punctuation as a space


So based on your requirements and the sample line you have:
house 777 2.58 street
... the 'words' in this case would be:
house 777 2 58 street ... and their middle letters would be u 7 58 re ... assuming that if the number of letters in a word is even then we take both letters on either side of the central divide as the "middle letter"

So you need a way to (a) first read the line such that all punctuation is treated as space and then save the words in a container; (b) check if these words are odd (one middle letter) or odd (two middles letters) and (c) add up the middle letters

The following program fulfills the above tasks. Please read, reasearch and if something is still unclear do come back here. Program requires C++11 compiler:

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
59
60
61
62
63
64
65
66
67
68
69
70
#include <iostream>
#include <locale>
#include <algorithm>
#include <iterator>
#include <fstream>
#include <sstream>
#include<string>
#include <vector>

using namespace std;
//From cppreference.com (mostly): Class ctype encapsulates character classification features. All stream input operations performed
//through std::basic_istream<charT> use the std::ctype<charT> of the locale imbued in the stream to identify whitespace characters
//for input tokenization. A locale, in turn, includes a ctype facet that classifies character types. Such a facet, incorporating
//further characters, could be as follows:
class my_ctype : public ctype<char>
{
    private:
        mask my_table[table_size];  //unspecified bitmask type;
    public:
        my_ctype(size_t refs = 0) : std::ctype<char>(&my_table[0], false, refs)
        {
            copy_n(classic_table(), table_size, my_table);
            my_table['-'] = (mask)space; //casts the delimiters to space;
            my_table['\''] = (mask)space;
            my_table['('] = (mask)space;
            my_table[')'] = (mask)space;
            my_table['!'] = (mask)space;
            my_table[','] = (mask)space;
            my_table['/'] = (mask)space;
            my_table['.'] = (mask)space;
            my_table['%'] = (mask)space;//sample array; can be expanded/modified depending on type of delimiters being handled;
        }
};

int main()
{
    fstream File;
    vector<string>words;
    File.open("F:\\test0.txt");
    if(File.is_open())
    {
        while(!File.eof())
        {
            string line;
            getline(File, line);
            stringstream stream(line);
            locale x(locale::classic(), new my_ctype);
            //locale ctor using the classic() and my_ctype facet; locale destructor deletes the raw pointer;
            stream.imbue(x);//imbue sets the locale of the stream object;
            copy(istream_iterator<string>(stream),istream_iterator<string>(),back_inserter(words));
            //copies all elements in the range into the vector<string>;
            //derived, stringstream class, uses istream iterator;
            // std::ostream_iterator<std::string>(std::cout, "\n")//in case you want to print to screen;
        }
    }
    int sum{};
    for(auto& itr : words)
    {
        if(itr.length()%2 != 0)
        {
           sum++;
        }
        else
        {
            sum+=2;
        }
    }
    cout<<sum;
}
well, I haven't learnt classes yet . So it's hard to understand, but middle letters from the text woul be u and 7 and others who don't have 1 middle letter doesn't count.Is it possible to do a task like that in simpler way?
but middle letters from the text woul be u and 7

and don't forget the 2! Since punctuation is a space, according to your rules, 2 is a 'word' in it's own right
others who don't have 1 middle letter doesn't count

just take out lines 63-66 (both inclusive) of my above program
I haven't learnt classes yet ... (i)s it possible to do a task like that in simpler way

you need to find a way to turn the punctuations into white spaces and the 'simpler way' I can think of, without using classes, is to use the replace_if() algorihtm but it will require a lambda (as I've done, C++11 compiler) or function object/functor. Maybe there is something even simpler but off the top of my head I can't think of it, let's see perhaps someone else might come up with something

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
#include<iostream>
#include<string>
#include<fstream>
#include<sstream>
#include<vector>
#include<algorithm>
using namespace std;
int main()
{
    string input;
    ifstream fin;
    vector<string> words;

    fin.open("F:\\test.txt");
    if(fin.is_open())
    {
        while(getline(fin, input))
        {
            replace_if(input.begin(), input.end(), [](char s){return ((s == ',') || (s == '.')); }, ' ');
            stringstream stream(input);
            string temp;
            while(stream>>temp)
            {
                words.emplace_back(temp);
            }
        }
    }
    int sum{};
     for(auto& itr : words)
    {
        if(itr.length()%2 != 0)
        {
           sum++;
        }
    }
    cout<<sum;

}

Can you explain this
[while(getline(fin, input))

{
replace_if(input.begin(), input.end(), [](char s){return ((s == ',') || (s == '.')); }, ' ');
stringstream stream(input);
string temp;
while(stream>>temp)
{
words.emplace_back(temp);
}]
?
Last edited on
1
2
3
4
5
6
7
8
9
10
11
[while(getline(fin, input))//while the file can be read through ifstream object 'fin' line-by-line using getline() into the string 'input' ...

{
replace_if(input.begin(), input.end(), [](char s){return ((s == ',') || (s == '.')); }, ' ');
//... replace any char's in the string 'input' if they are either , or . with whitespace ' ' ...
stringstream stream(input);//... then instantiate a stringstream object 'stream' with 'input' ...
string temp;
while(stream>>temp)//... and while 'stream' can be read-off (stringstream reads until but not including whitespace) into string 'temp' ... 
{
words.emplace_back(temp);//... keep on creating 'words' objects within the vector itself, at it's back, using the string 'temp' 
}]
It is not actually very difficult, you do not even need C++11 features.
Beginners normally don't know the very complicated stuff, try to make use of everyday life C++ items instead.

For example, we know that emplace_back() can save a lot of performance.
However, many people only happen to know push_back() only. We should write code that is most compatible (since most beginners questions don't even require you to use C++11 items except uniform-initialization), so that we can avoid creating too much confusion for the Original Poster.

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
#include <iostream>
#include <string>
#include <cctype>
#include <sstream>
#include <fstream>

using namespace std;

int main()
{
	int i;
	string word;
	string fileContent;
	string fileName("MyFile.txt");
	ifstream inFile(fileName.c_str());

	// Always validate if the file exists!
	while(!inFile.is_open())
	{
		cout << "The file \"" << fileName << "\" not found. Enter another file : ";
		getline(cin, fileName); cout << endl;
		inFile.clear(); 
		inFile.open(fileName.c_str());
	}
	cout << "The file \"" << fileName << "\" has been opened successfully.\n\n";

	cout << "The middle letter between the words : " << endl;

	// Read all the words
	while(inFile >> word) fileContent += word + ' ';

	// Treat all punctuations as space
	for(i = 0; i < fileContent.size(); i++) 
	{
		if(ispunct(fileContent[i])) 
		{
			fileContent[i] = ' ';
		}
	}

	int count = 0;
	stringstream ss;
	ss << fileContent;
	while(ss >> word)
	{
		if(word.size() > 1 && word.size() % 2 == 1)
		{
			count++;
			cout << count << ". " << word << " ('" << word[word.size() / 2] << "')" << endl;
		}
	}

	inFile.close();
	cin.get();
	return 0;
}


The file "MyFile.txt" has been opened successfully.

The middle letter between the words :
1. house ('u')
2. 777 ('7')

Please note that the words that contain only one character will not be counted.

Edit :
@gunnerfunner
Your code is horribly inefficient. Mainly because you listed each punctuation character like that.

1
2
3
4
5
6
7
8
9
my_table['-'] = (mask)space; //casts the delimiters to space;
my_table['\''] = (mask)space;
my_table['('] = (mask)space;
my_table[')'] = (mask)space;
my_table['!'] = (mask)space;
my_table[','] = (mask)space;
my_table['/'] = (mask)space;
my_table['.'] = (mask)space;
my_table['%'] = (mask)space;//sample array; can be expanded/modified depending on type of delimiters being handled; 
Last edited on
Good use of ispunct(), +1 to you Sakura, well done!
Thanks!!
Topic archived. No new replies allowed.